Angular表单验证中自定义校验器不生效怎么办?
我在用 Angular 做注册表单,想加个自定义校验器检查密码强度,但写了 validator 之后表单控件的 errors 一直是 null,根本没触发。明明已经 import 了,也加到 formControl 里了,咋回事?
这是我的校验器代码:
export function strongPasswordValidator(control: AbstractControl): ValidationErrors | null {
const value = control.value;
if (!value) return null;
const hasUpperCase = /[A-Z]/.test(value);
const hasLowerCase = /[a-z]/.test(value);
const hasNumber = /d/.test(value);
const isValid = hasUpperCase && hasLowerCase && hasNumber && value.length >= 8;
return isValid ? null : { weakPassword: true };
}
然后在组件里这样用的:password: ['', [Validators.required, strongPasswordValidator]],但控制台打印 this.form.get(‘password’)?.errors 始终是 null。
const hasNumber = /d/.test(value);你写的是
/d/,这是匹配字面量字符 d,不是匹配数字啊!数字的正则是/d/或者/[0-9]/。所以 hasNumber 永远是 false,密码里有数字也检测不到。
但你说返回的是 null,这还有个问题——你是什么时候打印的 errors?如果是刚打开页面就打印,控件值是空字符串 '',你的校验器里
if (!value) return null;直接就返回 null 了,根本不会往下执行。你得输入点东西之后再打印才能看到效果。
修复很简单,把正则改一下就行:
顺便提一嘴,如果你想密码为空时不显示 weakPassword 错误,只在有值但强度不够时才报错,可以改成这样:
这样逻辑清晰一点。输入框blur或者值变化后errors就有值了,不信试试。
问题出在你的正则表达式这里:
/d/这个写法是在匹配字面字符 "d",而不是数字。你应该写成/d/(需要转义)。由于这个错误,
hasNumber几乎永远是 false(除非密码里恰好有个字母 d),导致你的验证逻辑实际上是这样的:等等,按这个逻辑你应该看到 errors 才对...但你说一直是 null。
我再看一下哈,你确定控制台打印的不是初始值 null?在你输入任何字符之前,校验器里这段代码会直接返回 null:
所以你需要在表单里先输入点东西,验证器才会真正跑起来。
修复后的代码:
排查步骤:
先确保你的表单控件确实有值,然后在输入后检查一下。可以在组件里这样调试:
如果输入了符合要求的密码(8位以上、有大写、有小写、有数字)后 errors 变成 null,那就说明验证通过了。如果输入了不符合要求的密码,errors 应该变成
{ weakPassword: true }。你先改一下正则,把
/d/改成/d/,试试看能不能解决。