如何触发响应式表单中输入的验证?
How can I trigger validations for inputs in ReactiveForms?
我在 Reactive Forms 中开发了一个表单,用户可以在其中设置新密码。他输入旧密码和新密码并确认新密码。
我考虑过以下情况:
- 新密码不能包含旧密码
- 新密码和确认密码匹配
开发工作也很好。现在我有一件事不太好。仅当我更改输入字段中的某些内容时才会触发验证。但是现在想确认密码的时候要修改新密码,这样才知道有没有错误。我读到这可以通过函数 updateValueAndValidity 来完成。你知道怎么做吗?
我的代码:
// TS
changePasswordForm: FormGroup;
submitted = false;
ngOnInit() {
// To initialize forms
this.initChangePasswordForm();
}
// Creation of the changePasswordForm
private initChangePasswordForm() {
// General
this.changePasswordForm = this.formBuilder.group({
old_password: [null, Validators.pattern('^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^\w\s]).{8,}$')],
new_password: [null, this.customComparePasswordValidator],
confirm_password: [null, Validators.required]
});
}
customComparePasswordValidator(control: FormControl) {
const newPassword = control.value;
if (newPassword && newPassword.length) {
const oldPassword = control.parent.value.old_password;
if (oldPassword && oldPassword.length && newPassword.toLowerCase().includes(oldPassword.toLowerCase())) {
return { newPasswordIncludesOldPassword: true };
}
const pattern = new RegExp('^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^\w\s]).{8,}$');
if (!pattern.test(newPassword)) {
return { newPasswordInvalid: true };
}
} else {
return { required: true };
}
}
// HTML
<input matInput type="password" placeholder="aktuelles Passwort" formControlName="old_password" required>
<p *ngIf="changePasswordForm.get('old_password').invalid && (changePasswordForm.get('old_password').dirty || changePasswordForm.get('old_password').touched)">
<mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('old_password').hasError('required')">aktuelles Passwort eingeben</mat-error>
<mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('old_password').hasError('pattern')">8 oder mehr Zeichen mit einer Mischung aus Groß- und Kleinbuchstaben, Ziffern und Symbolen verwenden</mat-error>
</p>
<input matInput type="password" placeholder="neues Passwort" formControlName="new_password" required>
<p *ngIf="changePasswordForm.get('new_password').invalid && (changePasswordForm.get('new_password').dirty || changePasswordForm.get('new_password').touched)">
<mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('new_password').hasError('required')">neues Passwort eingeben</mat-error>
<mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('new_password').hasError('newPasswordInvalid')">8 oder mehr Zeichen mit einer Mischung aus Groß- und Kleinbuchstaben, Ziffern und Symbolen verwenden</mat-error>
<mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('new_password').hasError('newPasswordIncludesOldPassword')">Neues und altes Passwort dürfen nicht gleich sein</mat-error>
</p>
<input matInput type="password" placeholder="Passwort bestätigen" formControlName="confirm_password" appConfirmEqualValidator="new_password" required>
<p *ngIf="changePasswordForm.get('confirm_password').invalid && (changePasswordForm.get('confirm_password').dirty || changePasswordForm.get('confirm_password').touched)">
<mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('confirm_password').hasError('required')">Passwort erneut eingeben</mat-error>
<mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('confirm_password').hasError('notEqual') && !changePasswordForm.get('confirm_password').hasError('required')">Passwort stimmt nicht überein</mat-error>
</p>
我的 StackBlitz:https://stackblitz.com/edit/example-angular-material-reactive-form-sr1keu?file=app%2Fapp.component.html
正如您所说,验证器仅在您更改 FormControl 时“检查”。因此,您可以在更改第二个控件时“强制”使一个控件生效。所以,例如你可以简单地做,在 FormControl "new_password" 中写
<input matInput ... formControlName="new_password"
(input)="changePasswordForm.get('confirm_password').updateValueAndValidity()" />
(与其他 FormControl 相同)
您也可以在创建表单后订阅 valueChanges -别忘了取消订阅-
private initChangePasswordForm() {
// After create the formGroup
this.changePasswordForm = this.formBuilder.group({..}
//subscribe to changes "new_password"
this.changePasswordForm.get('new_password').valueChanges
.subscribe(_=>{
this.changePasswordForm.get('confirm_password').updateValueAndValidity()
})
另一种方法是在整个表单上创建一个 customValidator。当你使用 material 时,你需要使用 setErrors。验证器可以像
validatorRepeatPassword(form: FormGroup) {
const errorOldPassword = {};
const errorNewPassword = {};
const errorConfirmPassword = {};
const pattern = new RegExp(
'^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^\w\s]).{8,}$'
);
if (!form.value.old_password) errorOldPassword['required'] = true;
else {
if (!pattern.test(form.value.old_password))
errorOldPassword['pattern'] =
'8 or more characters with a mixture of upper and lower case letters,use numbers and symbols';
}
if (!form.value.new_password) errorNewPassword['required'] = true;
else {
if (!pattern.test(form.value.new_password))
errorNewPassword['pattern'] =
'8 or more characters with a mixture of upper and lower case letters,use numbers and symbols';
if (
form.value.old_password &&
form.value.new_password
.toLowerCase()
.includes(form.value.old_password.toLowerCase())
)
errorNewPassword['newPasswordIncludesOldPassword'] = true;
}
if (!form.value.confirm_password) errorConfirmPassword['required'] = true;
else {
if (
form.value.new_password &&
form.value.confirm_password != form.value.new_password
)
errorConfirmPassword['notEqual'] = true;
}
form.controls.old_password.setErrors(
Object.keys(errorOldPassword).length ? errorOldPassword : null
);
form.controls.new_password.setErrors(
Object.keys(errorNewPassword).length ? errorNewPassword : null
);
form.controls.confirm_password.setErrors(
Object.keys(errorConfirmPassword).length ? errorConfirmPassword : null
);
return {
...errorOldPassword,
...errorNewPassword,
...errorConfirmPassword,
};
}
并使用
this.changePasswordForm = this.formBuilder.group(
{
old_password: null,
new_password: null,
confirm_password: null,
},
{ validator: this.validatorRepeatPassword }
);
最后一个方法(我只用new_password制作,确认密码是用两个控件制作验证器。像
这样的函数
matchValidator(field: string,not:boolean=false) {
return (control: AbstractControl) => {
const parent = control.parent;
const controlCompare = parent ? parent.get(field) : null;
if (controlCompare && controlCompare.value && control.value) {
const invalid = controlCompare.value != control.value;
if (invalid!=controlCompare.invalid)
{
setTimeout(()=>{
controlCompare.updateValueAndValidity();
})
}
return invalid && !not ? { match: 'no match' } : null;
}
};
}
允许我们写,例如
this.changePasswordForm = this.formBuilder.group(
{
old_password: null,
new_password: [null,this.matchValidator('confirm_password',true)],
confirm_password: [null,this.matchValidator('confirm_password',true)]
}
);
看到你用一个函数来传递参数-应该是固定的-
我在 Reactive Forms 中开发了一个表单,用户可以在其中设置新密码。他输入旧密码和新密码并确认新密码。 我考虑过以下情况:
- 新密码不能包含旧密码
- 新密码和确认密码匹配
开发工作也很好。现在我有一件事不太好。仅当我更改输入字段中的某些内容时才会触发验证。但是现在想确认密码的时候要修改新密码,这样才知道有没有错误。我读到这可以通过函数 updateValueAndValidity 来完成。你知道怎么做吗?
我的代码:
// TS
changePasswordForm: FormGroup;
submitted = false;
ngOnInit() {
// To initialize forms
this.initChangePasswordForm();
}
// Creation of the changePasswordForm
private initChangePasswordForm() {
// General
this.changePasswordForm = this.formBuilder.group({
old_password: [null, Validators.pattern('^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^\w\s]).{8,}$')],
new_password: [null, this.customComparePasswordValidator],
confirm_password: [null, Validators.required]
});
}
customComparePasswordValidator(control: FormControl) {
const newPassword = control.value;
if (newPassword && newPassword.length) {
const oldPassword = control.parent.value.old_password;
if (oldPassword && oldPassword.length && newPassword.toLowerCase().includes(oldPassword.toLowerCase())) {
return { newPasswordIncludesOldPassword: true };
}
const pattern = new RegExp('^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^\w\s]).{8,}$');
if (!pattern.test(newPassword)) {
return { newPasswordInvalid: true };
}
} else {
return { required: true };
}
}
// HTML
<input matInput type="password" placeholder="aktuelles Passwort" formControlName="old_password" required>
<p *ngIf="changePasswordForm.get('old_password').invalid && (changePasswordForm.get('old_password').dirty || changePasswordForm.get('old_password').touched)">
<mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('old_password').hasError('required')">aktuelles Passwort eingeben</mat-error>
<mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('old_password').hasError('pattern')">8 oder mehr Zeichen mit einer Mischung aus Groß- und Kleinbuchstaben, Ziffern und Symbolen verwenden</mat-error>
</p>
<input matInput type="password" placeholder="neues Passwort" formControlName="new_password" required>
<p *ngIf="changePasswordForm.get('new_password').invalid && (changePasswordForm.get('new_password').dirty || changePasswordForm.get('new_password').touched)">
<mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('new_password').hasError('required')">neues Passwort eingeben</mat-error>
<mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('new_password').hasError('newPasswordInvalid')">8 oder mehr Zeichen mit einer Mischung aus Groß- und Kleinbuchstaben, Ziffern und Symbolen verwenden</mat-error>
<mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('new_password').hasError('newPasswordIncludesOldPassword')">Neues und altes Passwort dürfen nicht gleich sein</mat-error>
</p>
<input matInput type="password" placeholder="Passwort bestätigen" formControlName="confirm_password" appConfirmEqualValidator="new_password" required>
<p *ngIf="changePasswordForm.get('confirm_password').invalid && (changePasswordForm.get('confirm_password').dirty || changePasswordForm.get('confirm_password').touched)">
<mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('confirm_password').hasError('required')">Passwort erneut eingeben</mat-error>
<mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('confirm_password').hasError('notEqual') && !changePasswordForm.get('confirm_password').hasError('required')">Passwort stimmt nicht überein</mat-error>
</p>
我的 StackBlitz:https://stackblitz.com/edit/example-angular-material-reactive-form-sr1keu?file=app%2Fapp.component.html
正如您所说,验证器仅在您更改 FormControl 时“检查”。因此,您可以在更改第二个控件时“强制”使一个控件生效。所以,例如你可以简单地做,在 FormControl "new_password" 中写
<input matInput ... formControlName="new_password"
(input)="changePasswordForm.get('confirm_password').updateValueAndValidity()" />
(与其他 FormControl 相同)
您也可以在创建表单后订阅 valueChanges -别忘了取消订阅-
private initChangePasswordForm() {
// After create the formGroup
this.changePasswordForm = this.formBuilder.group({..}
//subscribe to changes "new_password"
this.changePasswordForm.get('new_password').valueChanges
.subscribe(_=>{
this.changePasswordForm.get('confirm_password').updateValueAndValidity()
})
另一种方法是在整个表单上创建一个 customValidator。当你使用 material 时,你需要使用 setErrors。验证器可以像
validatorRepeatPassword(form: FormGroup) {
const errorOldPassword = {};
const errorNewPassword = {};
const errorConfirmPassword = {};
const pattern = new RegExp(
'^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^\w\s]).{8,}$'
);
if (!form.value.old_password) errorOldPassword['required'] = true;
else {
if (!pattern.test(form.value.old_password))
errorOldPassword['pattern'] =
'8 or more characters with a mixture of upper and lower case letters,use numbers and symbols';
}
if (!form.value.new_password) errorNewPassword['required'] = true;
else {
if (!pattern.test(form.value.new_password))
errorNewPassword['pattern'] =
'8 or more characters with a mixture of upper and lower case letters,use numbers and symbols';
if (
form.value.old_password &&
form.value.new_password
.toLowerCase()
.includes(form.value.old_password.toLowerCase())
)
errorNewPassword['newPasswordIncludesOldPassword'] = true;
}
if (!form.value.confirm_password) errorConfirmPassword['required'] = true;
else {
if (
form.value.new_password &&
form.value.confirm_password != form.value.new_password
)
errorConfirmPassword['notEqual'] = true;
}
form.controls.old_password.setErrors(
Object.keys(errorOldPassword).length ? errorOldPassword : null
);
form.controls.new_password.setErrors(
Object.keys(errorNewPassword).length ? errorNewPassword : null
);
form.controls.confirm_password.setErrors(
Object.keys(errorConfirmPassword).length ? errorConfirmPassword : null
);
return {
...errorOldPassword,
...errorNewPassword,
...errorConfirmPassword,
};
}
并使用
this.changePasswordForm = this.formBuilder.group(
{
old_password: null,
new_password: null,
confirm_password: null,
},
{ validator: this.validatorRepeatPassword }
);
最后一个方法(我只用new_password制作,确认密码是用两个控件制作验证器。像
这样的函数 matchValidator(field: string,not:boolean=false) {
return (control: AbstractControl) => {
const parent = control.parent;
const controlCompare = parent ? parent.get(field) : null;
if (controlCompare && controlCompare.value && control.value) {
const invalid = controlCompare.value != control.value;
if (invalid!=controlCompare.invalid)
{
setTimeout(()=>{
controlCompare.updateValueAndValidity();
})
}
return invalid && !not ? { match: 'no match' } : null;
}
};
}
允许我们写,例如
this.changePasswordForm = this.formBuilder.group(
{
old_password: null,
new_password: [null,this.matchValidator('confirm_password',true)],
confirm_password: [null,this.matchValidator('confirm_password',true)]
}
);
看到你用一个函数来传递参数-应该是固定的-