响应式表单自定义验证不适用于AngularBlur 7

时间:2018-12-20 04:41:38

标签: angular typescript

我在验证我在Angular 7中onBlur上的Confirm-pass字段时遇到问题。就我而言,我构建了多个自定义验证器,这些控件在控件被设置为“脏”后可以正常工作,以及在Pascal Prechts教程之后的指令仅在触摸字段时可以在onBlur上工作,但是我想要一个纯粹的Reactive解决方案,而Pascal要求将其添加到HTML。

问题示例:单击进入firstName字段,立即选项卡或单击out-内置必需的验证器将触发。 点击进入confirmPass字段,立即点击或跳出;自定义验证程序不会触发(即使控制台日志也未显示)。如果您要在制表符或单击之前键入任何单个字符,那么我制作的每个版本都可以使用。

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

接下来,我尝试了Pascal Prechts教程; https://blog.thoughtram.io/angular/2016/03/14/custom-validators-in-angular-2.html用作指令-我不得不在HTML中输入equalValidator-我不想这样做。

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

FormGroup

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 };
}

我希望我的函数在触摸和/或弄脏时可以运行,但是当前仅在弄脏时才运行。在理想的世界中,我希望能够纯粹通过FormBuilder声明使用我自己的自定义函数来扩展Validators或NG_VALIDATORS类。在这一点上,我认为它与多供应商和扩展NG_VALIDATORS有关,但是..即使是这种情况,我也不知道该怎么做。

1 个答案:

答案 0 :(得分:1)

在创建FormControl时,Angular会首先运行验证器,然后每次在FormControl中更改值。当您只聚焦和模糊输入时,就不会进行任何重新验证。

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

您需要做的是,只要confirmPass发生更改,就可以自己触发password表单控件的验证。做到这一点的一个好地方是valueChanges表单控件的password订阅。

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

Here,您将找到更新的stackblitz演示。