Angular 6 - Expected validator to return Promise or Observable in async validator

Michał Bil

In my Angular 6 app I have async validator for checking if typed email is already registered but right now I'm getting 'Expected validator to return Promise or Observable' and I don't really know why.

import { UserService } from '../user/service/user.service';
import { AbstractControl, ValidationErrors, AsyncValidator } from '@angular/forms';
import * as validationUtils from '../validation/validation-utils';
import { Injectable } from '@angular/core';
import { of, Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class EmailExistValidator implements AsyncValidator {
  constructor(private userService: UserService) {
  }

  validate(emailControl: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> {
    const email = emailControl.value;

    if (new RegExp(validationUtils.emailRegex).test(email)) {
      this.userService
      .checkIfEmailExist(email)
      .pipe(
        map(
        (data) => {
          return {emailExist: true};
        },
        (error) => {
          return null;
        }
      ));
    }
      return of(null);
  }
}

register-component.ts

  createForm(): FormGroup {
    return this.formBuilder.group({
      email: ['',
      [Validators.required, Validators.email],
      [EmailExistValidator.bind(this)]],
      username: ['', [Validators.required,
        Validators.pattern(validationUtils.usernameRegex)]],
      password: ['', [Validators.required,
        Validators.pattern(validationUtils.passwordRegex)]],
      repeatPassword: ['', [Validators.required]]
  }, {
    validator: EqualPasswordValidator.validate
  });
  }

Edit 17.08.2018 As @Paulie suggested I changed validator declaration in formbuilder from .bind to pointing to validate function and with some tweaks to his proposition now everything works!

Final code:

register-component.ts

  constructor(
    private formBuilder: FormBuilder,
    private userService: UserService,
    private emailExistsValidator: EmailExistsValidator,
    private usernameExistsValidator: UsernameExistsValidator) { }

  ngOnInit() {
    this.registerForm = this.createForm();
  }

  createForm(): FormGroup {
    return this.formBuilder.group({
      email: ['',
      [Validators.required, Validators.email],
      [this.emailExistsValidator.validate]],
      username: ['', [Validators.required,
        Validators.pattern(validationUtils.usernameRegex)],
        [this.usernameExistsValidator.validate]],
      password: ['', [Validators.required,
        Validators.pattern(validationUtils.passwordRegex)]],
      repeatPassword: ['', [Validators.required]]
  }, {
    validator: EqualPasswordValidator.validate
  });
  }

email-exists-validator.ts

import { UserService } from '../user/service/user.service';
import { AbstractControl, ValidationErrors, AsyncValidator } from '@angular/forms';
import * as validationUtils from './validation-utils';
import { Injectable } from '@angular/core';
import { of, Observable } from 'rxjs';
import { map, catchError } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class EmailExistsValidator implements AsyncValidator {
    static userService: UserService;

  constructor(private userService: UserService) {
    EmailExistsValidator.userService = userService;
  }

  validate(emailControl: AbstractControl): Promise<{ [key: string]: any } | null>
  | Observable<{ [key: string]: any } | null>  {

    const email = emailControl.value;

    if (new RegExp(validationUtils.emailRegex).test(email)) {
        return EmailExistsValidator.userService
        .checkIfEmailExist(email)
        .pipe(
          map(data => ({emailExist: true})),
          catchError(error => of(null))
        );
      }

      return of(null);

}
}
Paulie

RxJS's map don't take a second function argument.
I guess you want something like this:

if (new RegExp(validationUtils.emailRegex).test(email)) {
  return this.userService
  .checkIfEmailExist(email)
  .pipe(
    map(data => {emailExist: true}),
    catchError(error => null)
  );
}

return of(null);

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Async Validator Throw Expected validator to return Promise or Observable

Angular Custom Validator Error (Expected validator to return Promise or Observable)

Expected validator to return Promise or Observable

Angular Async Validator not working as expected

Angular 2 async validator

Angular 2.3.1 async custom validator promise doesn't resolve

Aysnc validator angular 6

What to return in the angular 2 async validator when using observables

Angular 4 Validator with an http observable

Angular 2 validator not working as expected

Angular pattern Validator is not working as expected

angular async validator object not found

Angular Formbuilder testing with Async Validator

Angular custom async validator not working

Angular2 Async validator

Implement Async validator on Angular FormControl

Angular 6 error: ValidatorFn expected to return a promise

Using Observable inside Custom Validator Angular

Angular 6: Observable async binding not working as expected after HttpErrorResponse

Async Validator not working with Template driven Forms in Angular

Angular Custom Async Validator Not Showing Error

Angular 2 async validator always invalid

Angular Async Validator on multiple form fields

Angular2 template driven async validator

Angular custom async validator with socket.io

Angular: Return Observable / ES6 Promise from FileReader

Custom Async Validator using an observable from ngrx store selector does not return 'null' unless I put take(1) operator

how to create custom lowercase validator in angular 6 ?

Angular 6 return Observable