Forms 向下键重置角度指令错误

Forms 向下键重置角度指令错误,forms,angular6,Forms,Angular6,我一直试图通过附加到字段的指令添加表单验证。指令在keyup和blur上得到调用。当前,当满足错误标准时,设置了一个错误,但我遇到了一个问题,输入另一个键将导致错误消息闪烁(消失并重新出现) 观察控制台中的元素。我可以看到,在按下键(press/hold)时,我的指令还没有被调用,但是ngvalid类如何被添加到输入中,错误消息被清除。松开键将触发我的指令并重置错误。我在html中尝试了不同的错误切换逻辑,但最终结果是相同的。如果我删除了keyup监听器并严格使用blur运行,我会得到类似的结果

我一直试图通过附加到字段的指令添加表单验证。指令在keyup和blur上得到调用。当前,当满足错误标准时,设置了一个错误,但我遇到了一个问题,输入另一个键将导致错误消息闪烁(消失并重新出现)

观察控制台中的元素。我可以看到,在按下键(press/hold)时,我的指令还没有被调用,但是ngvalid类如何被添加到输入中,错误消息被清除。松开键将触发我的指令并重置错误。我在html中尝试了不同的错误切换逻辑,但最终结果是相同的。如果我删除了keyup监听器并严格使用blur运行,我会得到类似的结果:输入错误值->单击输出导致错误->重新聚焦,keydown导致错误消失

组件HTML

<div [formGroup]="group">
    <label for="item?.keyName" class="input-label">{{item?.titleText}}</label>
    <input
        id="item?.keyName"
        name="name"
        type="text"
        data-id="textInput"
        [placeholder]="item?.placeHolder"
        zipCodeValidator
        [formControlName]="item?.keyName"
        required>

    <span [hidden]="!group.get(item?.keyName).dirty && !group.get(item?.keyName).errors?.zipCode">
          {{group.get(item?.keyName).errors?.zipCode}}
    </span>
</div>


预期的结果是,当设置错误时,错误消息应该保留,并且不会被指令之外的任何其他事件清除。

我不知道为什么
keyup
事件会导致这种行为。但是使用
input
事件而不是
keyup
将为您提供所需的行为

@HostListener('input'))
public onKeyUp():void{
这个.validateZipCode();
}
还有一件事

当邮政编码有效时,
validateZipCode()
函数将在
formControl.erros
上设置
{zipCode:null}
。但是,这仍然会导致formControl无效。
validateZipCode()
当邮政编码有效时,不应设置任何内容

private validateZipCode():void{
const formControl:AbstractControl=this.control.control;
让errorMessage:string=null;
如果(!formControl.value){
errorMessage=this.errorMessages.emptyValue;
}
if(!this.regex.test(formControl.value)){
errorMessage=this.errorMessages.badRegex;
}
如果(!errorMessage)返回;
/**如果还有其他错误,我们将保留它们*/
if(formControl.errors)
setErrors({…formControl.errors,zipCode:errorMessage});
其他的
setErrors({zipCode:errorMessage});
}
这是一个工作演示

除此之外,我强烈建议使用这是处理表单验证的一种有角度的方法,它将使您远离此类副作用。而且它需要更少的代码。比如,

zipCodeValidator:ValidatorFn=(控件:FormControl):ValidationErrors | null=>{
const regex:RegExp=newregexp(/^(?:\d{5})?$/);
如果(!control.value)返回{zipCode:“请输入一个值。”};
如果(!regex.test(control.value))返回{zipCode:'输入一个有效的5位美国邮政编码,例如48226'.};
返回null;
}
formCtrl=newFormControl(“,[Validators.required,this.zipCodeValidator]);

这里是一个自定义表单验证程序的工作演示

,因此我相信我发现了这个问题。因此,在没有实际分配验证器的情况下,手动使用指令设置错误将导致在更改输入时删除错误,因为表单更新并重新运行验证检查。设置验证器并将现有的验证逻辑移动到该方法中可以解决这个问题。这段代码可以被进一步清理,但我认为它能让人明白这一点。所以@ysf在推荐自定义验证器时是正确的。非常感谢你的帮助

@Directive({
    selector: '[zipCodeValidator]',
})

export class ZipCodeValidator {
    constructor(private control: NgControl) {}

    @HostListener('keyup')
    public onKeyUp(): void {
        this.validateZipCode();
    }

    @HostListener('blur')
    public onBlur(): void {
        this.validateZipCode();
    }

    private validateZipCode(): void {
        const formControl: AbstractControl = this.control.control;
        formControl.setValidators([this.testVal]);
    }

    private testVal(control: AbstractControl): { [key: string]: string } | null {
        const regex: RegExp = new RegExp(/^(?:\d{5})?$/);
        const errorMessages = {
            badRegex: 'Enter a valid 5-digit US zip code. E.g. 48226.',
            emptyValue: 'Please enter a value.',
        };

        let errorMessage: string = null;

        if (!control.value) {
            errorMessage = errorMessages.emptyValue;
        }

        if (!regex.test(control.value)) {
            errorMessage = errorMessages.badRegex;
        }

        return { 'zipCode': errorMessage };
    }
}

为了澄清这一点,keyup按预期工作。如果我删除了keyup监听器并严格使用blur id运行,会得到类似的结果:输入错误值->单击退出输入导致错误->重新聚焦和keydown导致错误消失。好的,我想我误解了你的问题。现在,我知道您希望将
zipCodeValidator
与角度
验证器
并排使用,例如
验证器。必需的
。因此,当运行
zipCodeValidator
时,来自
Validators.required
的错误不会消失,它是
{required:true}
。erros应该像
{required:true;zipCode:'输入一个有效的5位美国邮政编码。例如48226。}
我理解正确了吗?我已经根据上面的评论更新了我的答案。现在,
zipCodeValidator
不会删除其他错误。但是,我强烈建议使用自定义验证器方法(请参见上面的示例),因为使用指令可能会导致FormControl有效性状态出现意外行为。很抱歉延迟,我将在一分钟内尝试您的解决方案。我不明白为什么这个错误会在一瞬间被清除,但是在阅读了你上面的评论之后,我认为你可能是对的。仍然没有运气。在指令运行之前,似乎有东西清除了错误。我是不是错过了一些有棱角的东西?自定义验证器可以由不同的事件(如onBlur/keyUp)调用吗?我对每个事件进行不同的验证。
@Directive({
    selector: '[zipCodeValidator]',
})

export class ZipCodeValidator {
    constructor(private control: NgControl) {}

    @HostListener('keyup')
    public onKeyUp(): void {
        this.validateZipCode();
    }

    @HostListener('blur')
    public onBlur(): void {
        this.validateZipCode();
    }

    private validateZipCode(): void {
        const formControl: AbstractControl = this.control.control;
        formControl.setValidators([this.testVal]);
    }

    private testVal(control: AbstractControl): { [key: string]: string } | null {
        const regex: RegExp = new RegExp(/^(?:\d{5})?$/);
        const errorMessages = {
            badRegex: 'Enter a valid 5-digit US zip code. E.g. 48226.',
            emptyValue: 'Please enter a value.',
        };

        let errorMessage: string = null;

        if (!control.value) {
            errorMessage = errorMessages.emptyValue;
        }

        if (!regex.test(control.value)) {
            errorMessage = errorMessages.badRegex;
        }

        return { 'zipCode': errorMessage };
    }
}