Angular 5自定义密码匹配验证器遇TypeError:无法读取undefined的'password'属性
解决Angular Material密码匹配验证的TypeError问题(避免ReactiveForms/FormGroup)
嘿,我明白你不想用Reactive Forms的FormGroup来做这个验证的需求,咱们直接用模板驱动表单+自定义验证器类来搞定这个问题,顺便解决那个TypeError!
首先,先说说你遇到的TypeError大概率是因为:
- 验证器里没有正确获取到两个密码控件的引用
- 验证器的返回格式不符合Angular的要求
- 模板里没有正确把验证器绑定到合适的控件组上
步骤1:创建密码匹配验证器类
咱们写一个实现Validator接口的验证器,专门用来检查两个密码字段是否匹配:
import { Validator, AbstractControl, ValidationErrors } from '@angular/forms'; import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class PasswordMatchValidator implements Validator { validate(control: AbstractControl): ValidationErrors | null { // 获取密码和确认密码控件 const password = control.get('password'); const confirmPassword = control.get('confirmPassword'); // 先检查控件是否存在,避免TypeError if (!password || !confirmPassword) { return null; } // 如果两个字段值不匹配,返回错误对象 if (password.value !== confirmPassword.value) { return { passwordMismatch: true }; } // 匹配成功返回null return null; } }
这里关键是先判断控件是否存在,这能避免你遇到的TypeError——如果控件没正确找到,直接返回null就不会报错了。
步骤2:组件类准备
在你的组件里注入这个验证器,同时定义表单相关的属性(模板驱动表单用ngModel绑定):
import { Component, OnInit } from '@angular/core'; import { PasswordMatchValidator } from './password-match.validator'; @Component({ selector: 'app-password-form', templateUrl: './password-form.component.html', styleUrls: ['./password-form.component.css'] }) export class PasswordFormComponent implements OnInit { password: string = ''; confirmPassword: string = ''; constructor(public passwordMatchValidator: PasswordMatchValidator) { } ngOnInit(): void { } }
步骤3:Angular Material模板实现
用ngModelGroup把两个密码字段包裹起来,然后把咱们的验证器绑定到这个group上,这样就能实现跨字段验证,还不用全局的FormGroup:
<form #passwordForm="ngForm"> <div ngModelGroup="passwordGroup" [validator]="passwordMatchValidator"> <!-- 密码输入框 --> <mat-form-field appearance="fill"> <mat-label>密码</mat-label> <input matInput type="password" name="password" [(ngModel)]="password" required #passwordCtrl="ngModel"> <mat-error *ngIf="passwordCtrl.invalid"> 请输入密码 </mat-error> </mat-form-field> <!-- 确认密码输入框 --> <mat-form-field appearance="fill"> <mat-label>确认密码</mat-label> <input matInput type="password" name="confirmPassword" [(ngModel)]="confirmPassword" required #confirmPasswordCtrl="ngModel"> <mat-error *ngIf="confirmPasswordCtrl.invalid"> 请确认密码 </mat-error> <mat-error *ngIf="passwordForm.get('passwordGroup')?.hasError('passwordMismatch')"> 两次输入的密码不匹配 </mat-error> </mat-form-field> </div> <!-- 提交按钮 --> <button mat-raised-button color="primary" [disabled]="passwordForm.invalid"> 提交 </button> </form>
关键说明
- 用
ngModelGroup来包裹需要验证的两个字段,这样验证器就能拿到这两个控件的引用,避免TypeError - 验证器里先判断控件是否存在,防止因为控件未初始化导致的TypeError
- Angular Material的
mat-error可以通过表单或控件的hasError方法来显示对应的错误信息
这样设置后,当两次密码输入不一致时,就会显示“两次输入的密码不匹配”的错误,而且不会出现TypeError啦!
内容的提问来源于stack exchange,提问作者tmott13
相关产品推荐
相关产品推荐

