52

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

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 中输入字段上的 blur 选项,但这不会使我的控件出错,除非有办法将控件置于错误状态。

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

谢谢。

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

4

6 回答 6

78

编辑 2

正如Alex官方文档所说,Angular 5.0.0 版为您的 ngModel 提供了新选项updateOn: 'blur'

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

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


原来的

我使用指令删除焦点上的整个验证并在模糊事件后将其返回。它基于克里斯蒂安·德尚的回答。

我仅在模糊时更新有效性,因此如果值在焦点之前无效,则在之后将无效。但如果你开始输入,有效性将被更新。

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

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

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

另外,请继续关注这个关于 onBlur 验证的Angular 2 github 线程


编辑 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();
        }
    }
于 2017-02-01T07:03:16.057 回答
20

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

这也意味着valueChanges在模糊事件发生之前不会触发该表单控件。minlength下面是一个例子required

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>

演示

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

于 2017-11-05T10:00:13.643 回答
10

在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>
于 2016-09-13T02:51:49.980 回答
6

像这样:使用ngControl对象的属性。

 <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>
于 2015-12-27T13:52:49.690 回答
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();
    }
}

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

于 2017-02-10T01:44:24.207 回答
-11

您可以

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

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

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

于 2015-11-25T15:49:35.337 回答