Angular2 - FormControl 验证模糊

Posted

技术标签:

【中文标题】Angular2 - FormControl 验证模糊【英文标题】:Angular2 - FormControl Validation on blur 【发布时间】:2016-02-25 07:26:50 【问题描述】:

我正在考虑添加一些基本的电子邮件验证,以检查用户是否输入了正确的电子邮件地址。目前使用下面的方法,验证会随着用户键入而更新,输入一个字符后出现错误时看起来很奇怪。

validEmail(c: Control)
if(!c.value.match('[a-z0-9!#$%&\'*+/=?^_`|~-]+(?:\\.[a-z0-9!#$%&\'*+/=?^_`|~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?'))
  return 
    validEmail: true
  ;

return null;
    

ctrlEmailAddress: Control = new Control('', Validators.compose([
Validators.required, this.validEmail]));

我想知道是否可以触发字段模糊验证,例如在 angularJS 中:

ng-model-options=" updateOn: 'blur' "

我知道 html 中输入字段上的模糊选项,但这不会使我的控件出错,除非有办法将控件置于错误状态。

谁能帮我指出正确的方向?

谢谢。

编辑:我正在寻找 angular2 解决方案,而不是 angularJS 解决方案。

【问题讨论】:

【参考方案1】:

你可以

[class.has-error]="!form.controls['ctrlEmailAddress'].valid"

这将在您更改模型后立即添加 has-error 类。所以基本上你不需要模糊来进行验证检查。

这解决了 angular 2.0.0 beta 的问题;)

【讨论】:

这不能回答问题。该问题询问如何仅在模糊上进行验证。【参考方案2】:

编辑 2

正如Alex 和official documentation 所说,Angular 版本 5.0.0 为您的 ngModel updateOn: 'blur' 提供了新选项

this.email = new FormControl(null, 
   validators: Validators.required,
   updateOn: 'blur'
);

您还可以使用其他更新选项:change(默认)、blursubmit


原创

我使用指令删除焦点上的整个验证并在模糊事件后将其返回。它基于 Cristian Deschamps 的回答。

我只在模糊时更新有效性,所以如果值在焦点之前无效,它在焦点之后将无效。但如果你开始输入,有效性将被更新。

由于某些原因,清除顺序是有意义的,所以我先清除异步验证器。

任何提供的建议都会有所帮助 =)

import  Directive  from '@angular/core';
import  NgControl  from '@angular/forms';

@Directive(
  selector: '[validate-onblur]',
  host: 
    '(focus)': 'onFocus($event)',
    '(blur)': 'onBlur($event)'
  
)
export class ValidateOnBlurDirective 
    private validators: any;
    private asyncValidators: any;
    constructor(public formControl: NgControl) 
    
    onFocus($event) 
      this.validators = this.formControl.control.validator;
      this.asyncValidators = this.formControl.control.asyncValidator;
      this.formControl.control.clearAsyncValidators();
      this.formControl.control.clearValidators();
    

    onBlur($event) 
      this.formControl.control.setAsyncValidators(this.asyncValidators);
      this.formControl.control.setValidators(this.validators);
      this.formControl.control.updateValueAndValidity();
    

另外,请继续关注 Angular 2 github thread 关于 onBlur 验证


编辑 1

还有另一个问题 - 如果我只是单击该字段并在单击离开后 - 将调用验证。如果您有任何关于它的通知(或服务器调用) - 它会在您每次执行时出现。所以你可以添加wasChanged 属性并像这样使用它:

    @Directive(
        selector: '[validate-onblur]',
        host: 
            '(focus)': 'onFocus($event)',
            '(blur)': 'onBlur($event)',
            '(keyup)': 'onKeyup($event)',
            '(change)': 'onChange($event)',
            '(ngModelChange)': 'onNgModelChange($event)'
        
    )
    export class ValidationOnBlurDirective 
        private validators: any;
        private asyncValidators: any;
        private wasChanged: any;
        constructor(public formControl: NgControl) 
        
        onFocus($event) 
            this.wasChanged = false;
            this.validators = this.formControl.control.validator;
            this.asyncValidators = this.formControl.control.asyncValidator;
            this.formControl.control.clearAsyncValidators();
            this.formControl.control.clearValidators();
        
        onKeyup($event) 
            this.wasChanged = true; // keyboard change
        
        onChange($event) 
            this.wasChanged = true; // copypaste change
        
        onNgModelChange($event) 
            this.wasChanged = true; // ng-value change
        
        onBlur($event) 
            this.formControl.control.setAsyncValidators(this.asyncValidators);
            this.formControl.control.setValidators(this.validators);
            if (this.wasChanged)
                this.formControl.control.updateValueAndValidity();
        
    

【讨论】:

这种方法的问题是,如果控件在获得焦点时无效且脏,那么在第一次击键之后(我正在考虑输入文本框)它将有效验证器,并且将应用 ng-valid 类。例如,如果您将该类设置为将输入框显示为绿色,那就有问题了。我认为只要控件保持焦点,它就应该保持某种挂起状态,因此不应用 ng-valid。 @DanielFranciscoSabugal 是的,这可能是个问题,但就我而言,这是一个不错的决定。用户在输入时不应该看到错误,并且在他结束后将被验证。 @AlexShestakov 感谢这篇文章。对我来说,this.formControl.control.validator(和 asyncValidator)返回 null。我正在使用有效验证的现有反应式表单上执行此操作。有什么想法吗? 看来我在尝试 this.formControl.control.validators [复数] 而不是 this.formControl.control.validator 如果你使用FormBuilder应该怎么做?【参考方案3】:

Angular v 5.0.0 开始,现在可以通过将 updateOn: 'blur' 标记到表单控件来实现。

这也意味着valueChanges 在模糊事件发生之前不会触发该表单控件。这是minlengthrequired 的示例:

this.form = new FormGroup(
  username: new FormControl('', 
  validators: [Validators.required, Validators.minLength(6)], updateOn: 'blur' )
)

get username() 
  return this.form.get('username');

您希望在模板中标记验证消息不会显示,除非该字段为touched

<div *ngIf="username.hasError('minlength') || username.hasError('required') 
              && username.touched">Required and minlength 6!
</div>

DEMO

P.S 如果需要,您还可以在整个表单上标记它,而不仅仅是在特定的表单控件上

【讨论】:

使用此语法时,FormControl 构造函数中的第二个参数为 AbstractControlOptions 类型,异步验证器设置如下: this.form = new FormGroup( username: new FormControl('', 验证器:[Validators.required, Validators.minLength(6)], asyncValidators: yourAsyncFunction, updateOn: 'blur' ) ) 如果你使用FormBuilder应该怎么做? 任何希望它与 Validator.compose() 一起工作的人都可以参考这个***.com/questions/50103342/…【参考方案4】:

我已经改进了一点 Alex Shestakov 解决方案,顺便说一下,它已经起作用了,以避免在保持焦点的同时将控制状态设置为有效。

@Directive(
    selector: '[validate-onblur]',
    host: 
        '(focus)': 'onFocus($event)',
        '(blur)' : 'onBlur($event)'
    
)
export class ValidateOnBlurDirective 

    private validators: any;
    private asyncValidators: any;
    private hasFocus = false;

    constructor(public formControl: NgControl) 
    

    onFocus($event) 
        this.hasFocus = true;
        this.validators = this.formControl.control.validator;
        this.asyncValidators = this.formControl.control.asyncValidator;
        this.formControl.control.clearAsyncValidators();
        this.formControl.control.clearValidators();
        this.formControl.control.valueChanges
            .filter(() => this.hasFocus)
            .subscribe(() => this.formControl.control.markAsPending());
    

    onBlur($event) 
        this.hasFocus = false;
        this.formControl.control.setAsyncValidators(this.asyncValidators);
        this.formControl.control.setValidators(this.validators);
        this.formControl.control.updateValueAndValidity();
    

这样,只要保持焦点,控件就会一直处于挂起状态。这将有助于避免控件在获得焦点之前无效,然后一旦用户开始在其上输入,它就被标记为有效,在模糊事件发生之前,再次设置验证器并且真正的有效性应该确定控制。

【讨论】:

【参考方案5】:

在 rc6 中找到了一种方法。

1- 创建指令:validate-onblur.directive.ts

@Directive(
  selector: '[validate-onblur]',
  host: 
    '(focus)': 'onFocus($event)',
    '(blur)': 'onBlur($event)'
  
)
export class ValidateOnBlurDirective 
    constructor(public formControl: NgControl) 
    

    onFocus($event) 
      this.formControl.control.markAsUntouched(false);
    

    onBlur($event) 
      this.formControl.control.markAsTouched(true);
    

然后在您的 html 模板中将指令添加到您的表单中,我的示例使用 ReactiveFormsModule 模型。

然后将此添加到您的错误消息中:

<input type="text" formControlName="full_name" validate-onblur />

<span *ngIf="formAccountDetails.controls.full_name.touched && !formAccountDetails.controls.full_name.valid && !formAccountDetails.controls.full_name.pristine" class="errors">
        ...
</span>

【讨论】:

【参考方案6】:

类似这样的: 使用 ngControl 对象的属性 touched

 <div class="form-group" [class.has-error]="!name.valid && name.touched">
        <label for="name">Name</label>
        <input #name="ngForm" ngControl="name" name="name" type="text" class="form-control" required>
 </div>

【讨论】:

这在下次元素获得焦点时无济于事。 name.focus 在第一次触摸时获得其真实值,从第二次开始 - 验证指示器将在每次按键时显示。

以上是关于Angular2 - FormControl 验证模糊的主要内容,如果未能解决你的问题,请参考以下文章

Angular2 formControl用于选择多个

在新的 Angular 2 表单中将 NgModel 绑定到 FormControl

angular2表单验证本机警报[重复]

无法绑定到“formControl”,因为它不是“输入”的已知属性 - Angular2 Material Autocomplete 问题

如何在下拉angular2中获取标签字符串作为formControl值?

在angular2中向FormGroup添加多个验证器