[英]Angular Reactive forms don't wait for custom async validators
我的 angular-CLI 應用程序中有一個登錄組件。 我有字段電子郵件和密碼。 我創建了兩個自定義驗證 => 一個用於檢查用戶是否存在,另一個用於檢查密碼是否與用戶匹配。 我檢查了內置驗證器的工作情況,例如必填字段和有效電子郵件。 他們工作得很好。 問題是我的自定義驗證器僅在調用提交后才顯示錯誤。 反應式表單不會等待自定義異步驗證器解析。
這是我的代碼:
import {Component, OnInit} from '@angular/core';
import {FormGroup, FormBuilder, Validators} from '@angular/forms';
import {AuthService} from '../auth.service';
import {noUser, pwdMisMatch} from '../validators';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {
form: FormGroup;
submitted = false;
returnUrl: string;
constructor(private formBuilder: FormBuilder, public authService: AuthService) {
this.form = this.formBuilder.group({
email: ['', [Validators.required, Validators.email]],
password: ['', Validators.required],
},
{
validators: [noUser(authService, 'email'), pwdMisMatch(authService, 'email', 'password')]
, updateOn: 'blur'
}
);
}
ngOnInit() {
this.returnUrl = '/dashboard';
this.authService.logout();
}
get f() {
return this.form.controls;
}
onSubmit() {
this.submitted = true;
// stop here if form is invalid
if (this.form.invalid) {
return;
} else {
alert('Success');
}
}
}
這是我的自定義驗證器文件:
import {FormGroup} from '@angular/forms';
import {AuthResponse, AuthService} from './auth.service';
export function MustMatch(controlName: string, matchingControlName: string) {
return (formGroup: FormGroup) => {
const control = formGroup.controls[controlName];
const matchingControl = formGroup.controls[matchingControlName];
if (matchingControl.errors && !matchingControl.errors.mustMatch) {
// return if another validator has already found an error on the matchingControl
return;
}
// set error on matchingControl if validation fails
if (control.value !== matchingControl.value) {
matchingControl.setErrors({ mustMatch: true });
} else {
matchingControl.setErrors(null);
}
};
}
export function userExist(authservice: AuthService, controlName: string) {
return (formGroup: FormGroup) => {
const control = formGroup.controls[controlName];
if (control.errors && !control.errors.CheckUser) {
// return if another validator has already found an error on the matchingControl
return;
}
// set error on matchingControl if validation fails
authservice.checkUser(control.value).subscribe((res: AuthResponse) => {
if (res.ok) {
control.setErrors({ userExist: true });
} else {
control.setErrors(null);
}
});
};
}
export function noUser(authService: AuthService, controlName: string) {
return (formGroup: FormGroup) => {
const control = formGroup.controls[controlName];
if (control.errors && !control.errors.noUser) {
// return if another validator has already found an error on the matchingControl
return;
}
// set error on matchingControl if validation fails
authService.checkUser(control.value).subscribe((res: AuthResponse) => {
if (!res.ok) {
control.setErrors({ noUser: true });
} else {
control.setErrors(null);
}
});
};
}
export function pwdMisMatch(authService: AuthService, controlName: string, secureControlName: string) {
return (formGroup: FormGroup) => {
const control = formGroup.controls[controlName];
const secureControl = formGroup.controls[secureControlName];
if (control.errors || secureControl.errors && !secureControl.errors.pwdMisMatch) {
// return if another validator has already found an error on the matchingControl
return;
}
// set error on matchingControl if validation fails
authService.verifyPassword(control.value, secureControl.value).subscribe((res: AuthResponse) => {
if (!res.ok) {
secureControl.setErrors({ pwdMisMatch: true });
} else {
control.setErrors(null);
}
});
};
}
我試過這個答案,但問題沒有解決。 請幫忙。
更新:我的角度回購
Angular customValidator 函數應該返回錯誤或空值才能工作。
FormGroup 具有掛起狀態,您可以使用它來檢查異步驗證器是否已完成。
嘗試這個:
export function noUser(authService: AuthService, controlName: string) {
return (formGroup: FormGroup) => {
const control = formGroup.controls[controlName];
if (control.errors && !control.errors.noUser) {
// return if another validator has already found an error on the matchingControl
return;
}
// set error on matchingControl if validation fails
authService.checkUser(control.value).subscribe((res: AuthResponse) => {
if (!res.ok) {
return { noUser: true };
} else {
return null;
}
});
};
}
export function pwdMisMatch(authService: AuthService, controlName: string, secureControlName: string) {
return (formGroup: FormGroup) => {
const control = formGroup.controls[controlName];
const secureControl = formGroup.controls[secureControlName];
if (control.errors || secureControl.errors && !secureControl.errors.pwdMisMatch) {
// return if another validator has already found an error on the matchingControl
return;
}
// set error on matchingControl if validation fails
authService.verifyPassword(control.value, secureControl.value).subscribe((res: AuthResponse) => {
if (!res.ok) {
rerurn { pwdMisMatch: true };
} else {
return null;
}
});
};
}
onSubmit() {
this.submitted = true;
// stop here if form is invalid
if (this.form.pending && this.form.invalid) {
return;
} else {
alert('Success');
}
}
也許您應該將其標識為異步驗證器,如下所示:
constructor(private formBuilder: FormBuilder, public authService: AuthService) {
this.form = this.formBuilder.group(
{
email: ['', [Validators.required, Validators.email]],
password: ['', Validators.required],
},
{
asyncValidators: [noUser(authService, 'email'), pwdMisMatch(authService, 'email', 'password')]
, updateOn: 'blur'
}
);
}
您的異步驗證函數不返回 Promise 或 Observable 的問題
從角度文檔:
異步驗證器:接受控件實例並返回 Promise 或 Observable 的函數,該 Promise 或 Observable 隨后會發出一組驗證錯誤或 null。 您可以在實例化 FormControl 時將它們作為第三個參數傳入
不要在這里使用訂閱:
authservice.checkUser(control.value).subscribe()
改用 pipe() 轉換:
authservice.checkUser(control.value). pipe(map(res => res && res.ok ? ({ userExist: true }) : null ))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.