angular4:使用valueChanges observable进行自定义'等于'验证

时间:2017-11-05 05:11:26

标签: angular validation observable

我需要验证,检查email是否等于Email Confirm。 为此,我创建了一个类似于

的自定义验证
import { AbstractControl, ValidationErrors, FormGroup } from '@angular/forms';

export function ValidateEqual( equals: string ) {
  return ( control: AbstractControl ): ValidationErrors | null => {

    const equalsField = control.root.get( equals )
    if ( equalsField ) {

      equalsField.valueChanges.subscribe( value => {
        console.log( 'observable fired', value );
        // control.updateValueAndValidity( { onlySelf: true  , emitEvent: false } );
      } );
      if ( control.value !== equalsField.value ) {
        return { equals: true };
      }
    }
    return null;
  }
}

我的表单看起来像

this.loginForm = this.fb.group( {
  password: [ '', [
    Validators.required,
  ] ],
  email: [ '', [
    Validators.required,
    Validators.email,
  ] ],
  emailConfirm: [ '', [
    Validators.required,
    Validators.email,
    ValidateEqual( 'email' ),
  ] ]
} );

所以我在ValidateEqual()中传递字段以检查相等性作为参数。这很好。

以下情况失败:

1)

电子邮件:mattijs@foo.nl

确认电子邮件:mattijs@food.nl

*现在确认电子邮件显示错误,它不等于“电子邮件”。正确的。

2)

*现在我更改email字段以匹配confirm email字段。

电子邮件:mattijs@food.nl

确认电子邮件:mattijs@food.nl

* confirm email字段上的错误不会消失,因为它不知道任何更改。

我遇到的问题是,我尝试在等号字段上使用valueChanges observable来重新验证control字段,但是当我启用control.updateValueAndValidity()时在每个按键上以指数方式订阅,浏览器将崩溃。 IT确实会通知email confirm字段重新验证,因此它几乎可以正常工作......

有没有人知道如何只让它订阅一次并重新验证control字段而不再订阅(并再次......)?

4 个答案:

答案 0 :(得分:3)

这是检查两封电子邮件是否相同的方法 在您的验证等级类中编写此代码

export class emailValidation {
    static matchEmail(AC: AbstractControl){
        let email=AC.get('email').value;
        let emailConfirm=AC.get('emailConfirm').value;
        if(email!=emailConfirm){
            console.log(false);
        }
    }
}

并在您的组件中添加此代码

this.loginForm = this.fb.group( {
  password: [ '', [
    Validators.required,
  ] ],
  email: [ '', [
    Validators.required,
    Validators.email,
  ] ],
  emailConfirm: [ '', [
    Validators.required,
    Validators.email,
  ] ]
},
{
    validator:passwordValidation.matchPassword
    } );

答案 1 :(得分:2)

我建议您在github上查看ngx-validation。 它是一个小型的开源库,您既可以直接使用它,也可以将其分叉,或者只是看看它们是如何在那里完成的:

答案 2 :(得分:1)

问题是ValidatorFn放置在FormControl上显然只会在FormControl的值发生变化时进行检查。我们想要的是检查emailemailConfirm何时发生变化。为此,我们需要验证FormGroup而不仅仅是FormControl。因为ValidatorFn收到AbstractControl,这意味着我们的函数可以接收FormGroup,FormControl或FormArray。

static matches(form: AbstractControl){
    return form.get('email').value == form.get('emailConfirm').value ? null : {equals: true};
}

现在,在您的组件中,您仍然需要添加此验证器,它有点不同:

this.form = this.fb.group({...}, {validator: CustomValidator.matches});

正如您所看到的,我们可以将第二个对象作为参数传递给整个FormGroup

的验证器

在模板中,您将检查整个表单是否具有等于错误而不是单个FormControl:

<div *ngIf="form.hasError('equals')">The emails don't match</div>

答案 3 :(得分:0)

谢谢你们的好榜样。我有理由在表单上而不是在formControl上执行此操作,因为它不知道如何对其他控件做出反应/响应。

我稍作调整,以便控制在Equal验证器中比较的字段。 我还在field2控件上设置了错误,这样我就不必在我的字段下面的某处添加单独的错误消息(我使用Material design mat-form-fields):

interface IEmailMatchFields {
  field1: string;
  field2: string;
}
export class EmailMatch {

  fields: IEmailMatchFields;
  constructor( fields: IEmailMatchFields ) {
    this.fields = fields;
  }
  emailMatches( form: AbstractControl ) {

    if ( this.fields ) {
      if ( form.get( this.fields.field1 ).value == form.get( this.fields.field2 ).value ) {
        form.get( this.fields.field2 ).setErrors( { 'emailNotEq': false } );
        form.get( this.fields.field2 ).updateValueAndValidity( { onlySelf: true } );
        return null;
      } else {
        form.get( this.fields.field2 ).setErrors( { 'emailNotEq': true } );
        return { emailNotEq: true };
      }
    }
  }
}

export class MyComponent implements OnInit {
  emailMatch: EmailMatch;
  registerForm: FormGroup;

  constructor(
    private fb: FormBuilder
  ) {
    this.emailMatch = new EmailMatch( { field1: 'email', field2: 'emailConfirm' } );
  }

  ngOnInit(): void {
    this.registerForm = this.fb.group( {
      password: [ '', [
        Validators.required,
      ] ],
      email: [ '', [
        Validators.required,
        Validators.email,
      ] ],
      emailConfirm: [ '', [
        Validators.required,
        Validators.email,
      ] ]
    }, {
      validator: this.emailMatch.emailMatches.bind( this.emailMatch )
    } );
  }
}

我猜测代替field1field2你也可以传递2个formcontrols的引用,但是你必须将formcontrols添加到你的表单组等。 我认为发送密钥效果很好。