1

I have a problem, I don't get the asynchronous validation with the reactive forms in angular. I get to keep the query active when writing about the input and it brings me results but I can't send the error in the html. I am new in angular and I don't know what I would be missing in the code.

Component.ts

  this.registroForm = this.fb.group({
  nombre: ["", [Validators.required, Validators.pattern("[a-zA-Z ]*")]],
  apellido: ["", [Validators.required, Validators.pattern("[a-zA-Z ]*")]],
  username: [
    "",
    [Validators.required, this.validateEmailNotTaken.bind(this)]
  ],
  email: ["", [Validators.required, Validators.pattern(this.emailPattern)]],
  telefono1: [
    "",
    [
      Validators.required,
      Validators.maxLength(10),
      Validators.minLength(10),
      Validators.pattern("[0-9]*")
    ]
  ],
  condiciones: ["", [Validators.required]]
});

My Validation Function: Checks every time I write in the input, the server responds to me in the following way, when the name exists in the BD it brings me the data of that in an json array, but an empty array that is why the data.length. So if it is equal to one it should show the error. But the input writes anything and it is placed in red without showing a specific error (for the validation of material angular) and apart it does not show the error in whether it exists or name not available.

  validateEmailNotTaken(control: AbstractControl) {
let username = {
  user: control.value
};
return this.authService.buscarUserUsername(username).subscribe(
  (data: any) => {
    console.log(data.length);
    if (data.length === 1) {
      return { userNameExists: true };
    }
  },
  err => {
    console.log(err);
  }
);

HTML

<mat-form-field appearance="outline" color="accent">
           <mat-label>Usuario</mat-label>
           <input formControlName="username" matInput placeholder="Nombre de usuario">
           <mat-error *ngIf="registroForm.controls['username'].errors?.required">Este campo es obligatorio
           </mat-error>
           <mat-error *ngIf="registroForm.controls['username'].errors?.pattern">No es un nombre de usuario valido
           </mat-error>
           <mat-error *ngIf="registroForm.get('username').errors?.userNameExists">
             Nombre de usuario no disponible               </mat-error>

         </mat-form-field>
1
  • you have the async validator as part of normal validator. Async validator should be a third parameter --> username: ["", Validators.required, this.validateEmailNotTaken.bind(this)] Commented Sep 16, 2019 at 21:21

1 Answer 1

1

The issue is that you are attempting to return values from within subscribe(). Instead you should be returning an Observable<ValidationErrors | null> with the mapped response for this async validator. This can be achieved by using pipeable operators such as map and catchError:

validateEmailNotTaken(control: AbstractControl) {
  let username = {
    user: control.value
  };

  return this.authService.buscarUserUsername(username).pipe(
    map(data => {
      if (data.length === 1) {
        // return error
        return {
          userNameExists: true
        };
      }

      // return null for no errors
      return null;
    }),
    catchError(err => {
      // handle error
      console.log(err);
    })
  )
}

As a general rule, review the return types of Angular class/interfaces carefully. Anywhere you see a return type of Observable<T> you probably cannot use subscribe() and instead need to use pipeable operators.

Also as suggested in a comment make sure to property pass the validators to the form configuration:

username: ["", Validators.required, this.validateEmailNotTaken.bind(this)]

Hopefully that helps!

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.