首页 > 解决方案 > 反应式表单自定义验证不适用于Blur,Angular 7

问题描述

我在 Angular 7 中验证我的确认传递字段 onBlur 时遇到问题。在我的情况下,我构建了多个自定义验证器,这些验证器在控件被设置为“脏”后工作,以及遵循 Pascal Prechts 教程的指令,它在当字段只被触及,但我想要一个纯反应式解决方案,Pascal 需要添加到 HTML。

问题示例:点击进入名字字段,立即选项卡或点击退出 - 内置所需的验证器触发。点击进入confirmPass字段,立即点击或跳出;自定义验证器不会触发(甚至控制台日志也没有显示)。如果您要在制表符或单击之前键入任何单个字符,那么我制作的每个版本都可以正常工作。

我尝试使用多个静态方法构建一个验证器类。控制所有使用的一种方法('director'),该方法检查传入的字段名并适当地重定向。这直接返回了错误映射或空值而不是函数,当然没有用。

接下来我尝试了 Pascal Prechts 教程;https://blog.thoughtram.io/angular/2016/03/14/custom-validators-in-angular-2.html用作指令 - 但是我必须在 HTML 中输入 equalValidator - 我没有想做。

最后我尝试了 Angular 建议的函数和我在 StackOverflow 上找到的另一个函数,它们都返回一个函数;它本身返回错误映射或 null。

表单组

ngOnInit() {
    this.regForm = this.fb.group({
        firstName: ["", [Validators.required, Validators.minLength(2), Validators.maxLength(30)]],
        lastName: ["", [Validators.required, Validators.minLength(2), Validators.maxLength(30)]],
        email: ["", [Validators.required, Validators.email]],
        password: ["", [Validators.required, Validators.minLength(8), Validators.maxLength(55)]],
        confirmPass: ["", matchingInputsValidator], 
    }, { updateOn: 'blur' });
    this.lgnForm = this.fb.group({
        lgnEmail: ["", [Validators.required, Validators.email]],
        lgnPass: ["", Validators.required]
    }, { updateOn: 'blur' });
}

适用于 Blur 的 Pascals 解决方案,但仅作为指令

function validateEqualFactory(compare: string) : ValidatorFn {
    return (c: FormControl) => {
        // value of confirm password field
        let v = c.value;

        // value of compared field - in this case 'password'
        let e = c.root.get(compare);

        // Ternary operator -> return null if equal or error map if not equal/password does not exist
        return (e && v === e.value) ? null : { misMatch: true };
    };
}

@Directive({
    selector: '[validateEqual][formControl],[validateEqual][formControlName]',
    providers: [
        { provide: NG_VALIDATORS, useExisting: forwardRef(() => EqualValidator), multi: true }
    ]
})
export class EqualValidator implements Validator {
    validator: ValidatorFn;
    constructor() {
        this.validator = validateEqualFactory("password");
    }
    validate(c: FormControl) {
        return this.validator(c);
    }
}

最后是我最近进行的两次尝试,第一次是 Angular 文档官方推荐的变体

export function confirmPassVal(): ValidatorFn {
    return (control: AbstractControl): {[key: string]: any} | null => {
        console.log("Making it here 1", control);
        const passCtrl = control.root.get('password');
        console.log("Making it here 2: ", passCtrl);
        return (passCtrl && passCtrl.value === control.value) ? null : {"misMatch" : true };
    }
}

export const matchingInputsValidator: ValidatorFn = (control: AbstractControl): ValidationErrors | null => {
    let pass;
    control.root.get('password') ? pass = control.root.get('password').value : pass = null;
    let confirmPass = control.value;
    return pass === confirmPass ? null : { misMatch: true };
}

我希望我的函数在字段被触摸和/或脏时运行,但它目前仅在字段脏时运行。在一个理想的世界中,我希望能够使用我自己的自定义函数扩展 Validators 或 NG_VALIDATORS 类,这完全来自 FormBuilder 声明。在这一点上,我相信它与多提供者有关,并且扩展了 NG_VALIDATORS 但是....即使是这种情况,我也不知道该怎么做。

标签: angulartypescript

解决方案


Angular 在创建时第一次运行验证器FormControl,然后每次在该FormControl. 当您只关注和模糊输入时,不会进行重新验证。

对于required字段,它的工作方式如下:当您创建FormControl低谷时FormBuilder,它会得到验证,并且从一开始就存在错误。它只是不可见,因为尚未触摸输入。因为matchingInputsValidator错误不存在,因为两个字段在开始时是相同的,所以当您触摸输入时,不会显示错误。

您需要做的是在confirmPass表单控件password发生更改时自行触发验证。这样做的一个好地方是valueChanges订阅password表单控件。

this.password.valueChanges.subscribe(() => this.confirmPass.updateValueAndValidity());

在这里,您将找到更新的 stackblitz 演示。


推荐阅读