Angular表单验证中自定义校验器不生效怎么办?

文雯的笔记 阅读 9

我在用 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。

我来解答 赞 1 收藏
二维码
手机扫码查看
1 条解答
园园 Dev
看到你的问题了兄弟,这个 bug 藏得挺深的。

问题出在你的正则表达式这里:

const hasNumber = /d/.test(value);  // 这是错的!


/d/ 这个写法是在匹配字面字符 "d",而不是数字。你应该写成 /d/(需要转义)。

由于这个错误,hasNumber 几乎永远是 false(除非密码里恰好有个字母 d),导致你的验证逻辑实际上是这样的:

const isValid = hasUpperCase && hasLowerCase && false && value.length >= 8;
// isValid 永远是 false

return isValid ? null : { weakPassword: true };
// 应该返回 { weakPassword: true } 才对


等等,按这个逻辑你应该看到 errors 才对...但你说一直是 null。

我再看一下哈,你确定控制台打印的不是初始值 null?在你输入任何字符之前,校验器里这段代码会直接返回 null:

if (!value) return null;


所以你需要在表单里先输入点东西,验证器才会真正跑起来。

修复后的代码:

import { AbstractControl, ValidationErrors } from '@angular/forms';

export function strongPasswordValidator(control: AbstractControl): ValidationErrors | null {
const value = control?.value;

// 空值时不验证,让 required 校验器来处理
if (!value) {
return null;
}

const hasUpperCase = /[A-Z]/.test(value);
const hasLowerCase = /[a-z]/.test(value);
const hasNumber = /d/.test(value); // 这里是关键:需要反斜杠
const hasMinLength = value.length >= 8;

// 全部满足才返回 null(验证通过),否则返回错误对象
const isValid = hasUpperCase && hasLowerCase && hasNumber && hasMinLength;

return isValid ? null : { weakPassword: true };
}


排查步骤:

先确保你的表单控件确实有值,然后在输入后检查一下。可以在组件里这样调试:

ngOnInit() {
this.form = this.fb.group({
password: ['', [Validators.required, strongPasswordValidator]]
});

// 监听值变化,看看验证器有没有返回错误
this.form.get('password')?.valueChanges.subscribe(value => {
console.log('当前值:', value);
console.log('errors:', this.form.get('password')?.errors);
});
}


如果输入了符合要求的密码(8位以上、有大写、有小写、有数字)后 errors 变成 null,那就说明验证通过了。如果输入了不符合要求的密码,errors 应该变成 { weakPassword: true }

你先改一下正则,把 /d/ 改成 /d/,试试看能不能解决。
点赞
2026-03-10 22:13