Estoy usando Angular 11 y creando una forma reactiva simple con un nombre de control de formulario 'nombre'. cuando el usuario escribe en este campo, necesito validar la unicidad. Intenté seguir pero se valida cada vez que escribo algo, pero quiero usar el tiempo de rebote y usar una lógica similar. No estoy seguro de cómo hacer esto con la forma reactiva
¿Alguien puede ayudarme a lograr esto?
Termino con el siguiente AsyncValdator. ¿Alguien puede ayudarme si esto se puede simplificar? Porque estoy pasando el servicio al método. ¿Hay alguna manera de usar la inyección de dependencia aquí?
export class TemplateNameValidator { createValidator(auditTemplateService: AuditTemplateService): AsyncValidatorFn { console.log("Static factory call"); return (control: AbstractControl): Observable<ValidationErrors> => { if(isEmptyInputValue(control.value)) { return of(null); } else { return control.valueChanges.pipe( debounceTime(500), distinctUntilChanged(), take(1), switchMap((name: string) => auditTemplateService.isNameUnique(name) .pipe( map(isUnique => !isUnique ? { 'duplicate': true } : null) ) ) ); } }; } } function isEmptyInputValue(value: any): boolean { return value === null || value.length === 0; } private registerFormGroup(): void { this.nameField = new FormControl( { value: this.auditTemplate.title, disabled: true }, [Validators.compose([ Validators.required, (control) => this.isNameUnique(control as AbstractControl) ])] ); this.templateForm = this.formBuilder.group({ templateName: this.nameField, tags: [this.auditTemplate.tags] }); }validación para comprobar la unicidad:
isNameUnique(formField: AbstractControl): { [key: string] : any} { const nameEntered = formField.value; let isDuplicate = false; if(nameEntered && this.availableNames) { const index = this.availableNames.findIndex(templateName => templateName.name === nameEntered); if(index !== -1) { isDuplicate = true; } } return isDuplicate ? { 'duplicate': true } : null; }Gracias
Estoy seguro de que hay muchas soluciones a este problema y se describe en pocas palabras en la documentación https://angular.io/guide/form-validation#implementing-a-custom-async-validator .
Sin embargo, no es muy obvio cómo usar validadores asíncronos. Entonces, un ejemplo mínimo podría verse así:
const myValidator: AsyncValidatorFn = (control: AbstractControl) => of(control.value) .pipe( delay(1000), map(value => { if (value === '1') { return null; } return { invalid: true } as ValidationErrors; }), tap(console.log), finalize(() => console.log('async validator unsubscribed')), ); @Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { control = new FormControl('', Validators.required, myValidator); }Demostración en vivo: https://stackblitz.com/edit/angular-ivy-mk4wyv?file=src%2Fapp%2Fapp.component.ts
El validador toma el valor más reciente del control , lo retrasa y luego realiza alguna verificación. En este caso, el validador pasa solo cuando escribe "1" en el campo de entrada.
Tenga en cuenta que el rebote lo realiza delay() y no se usa el operador debounceTime() . Esto se debe a que el método de validación se invoca en cada cambio de valor de control y necesita devolver un Observable que emite y completa. Si hubiera otro Observable de validación pendiente, Angular lo cancelará y se suscribirá al nuevo Observable. Es por eso que verá muchos registros de 'async validator unsubscribed' en la consola.
Una última cosa, los validadores asíncronos se pasan a FormControl como otro parámetro, no entre los validadores regulares:
new FormControl('', Validators.required, myValidator)