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);
}
}
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)]],
});
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With