Angular 6 - Expected validator to return Promise or Observable in async validator
16,534
Solution 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);
Solution 2
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)]],
});
Solution 3
You have to return the observable from checkIfEmailExist
:
// ...
return this.userService
.checkIfEmailExist(email)
.pipe(
// ...
Related videos on Youtube
Author by
Michał Bil
Updated on September 16, 2022Comments
-
Michał Bil over 1 year
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 over 5 yearsAre there any console errors?
.bind(this)
may mess up with theuserService
injector. Try to remove it. -
Michał Bil over 5 yearsYeah you was right. Bind was causing errors in this case. I edited my question with final working version.
-
Dragos Durlut over 5 years+1 for the return of(null). Still have to understand exactly what it does, but it fixed the error for me. I was returning just null.
-
Paulie over 5 years
of(null);
creates the RxJS Subject (object you can.subscribe()
) which always 'sends'null
(or other value/value sequence in you specify in the parameter) to the Subscriber. learnrxjs.io/operators/creation/of.html