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

末鹿安然 提交于 2019-12-07 23:54:37

问题


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);

}
}

回答1:


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);



回答2:


You have to return the observable from checkIfEmailExist:

// ...
return this.userService
  .checkIfEmailExist(email)
  .pipe(
// ...



回答3:


When you add multiple validators, then you need to add your validators inside another third bracket '[]' . Like Below:

this.yourForm= this.formBuilder.group({
    amount: [null, [Validators.required, Validators.min(1)]],
});


来源:https://stackoverflow.com/questions/51864074/angular-6-expected-validator-to-return-promise-or-observable-in-async-validato

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!