web-dev-qa-db-ja.com

Angular2のクロスフィールド検証

Angular2クライアントサイドアプリケーションを構築しています。現在、メンバーシップコンポーネントに取り組んでおり、クライアント側コンポーネントをMVC6 vNext Identity v3と統合しています。次のように、カスタムのAngular2パスワード検証ツールを作成しました。

needsCapitalLetter(ctrl: Control): {[s: string]: boolean} {
    if(!ctrl.value.match(/[A-Z]/))
        return {'needsCapitalLetter': true}

    return null;
}

needsLowerLetter(ctrl: Control): {[s: string]: boolean} {
    if(!ctrl.value.match(/[a-z]/))
        return {'needsLowerLetter': true}

    return null;            
}

needsNumber(ctrl: Control): {[s: string]: boolean} {
    if(!ctrl.value.match(/\d/))
        return {'needsNumber': true}

    return null;            
}

needsSpecialCharacter(ctrl: Control): {[s: string]: boolean} {
    if(!ctrl.value.match(/[^a-zA-Z\d]/))
        return {'needsSpecialCharacter': true}

    return null;            
}

これはうまく機能し、Angular2が大好きですが、今は「パスワードの確認」が「パスワード」と等しいことを検証するバリデーターを作成しようとしています。これを行うには、1つのフィールドを他のフィールドに対して検証できる必要があります。これはコンポーネントレベルで簡単に行うことができ、ぼかし、送信、またはその他のさまざまな方法で確認するだけですが、これはAngular2 ngForm検証システムをバイパスします。他のフィールドの名前またはこれに近いものを渡すことにより、別のフィールドの値を確認できるフィールドのAngular2 Validatorを書く方法を非常に知りたいです。これは、ほとんどすべての複雑なビジネスアプリケーションUIで必要になるため、機能である必要があります。

19
Coaden

これを実装するには、完全なフォームグループにカスタムバリデーターを割り当てる必要があります。このようなもの:

this.form = this.fb.group({
  name:  ['', Validators.required],
  email: ['', Validators.required]
  matchingPasswords: this.fb.group({
    password:        ['', Validators.required],
    confirmPassword: ['', Validators.required]
  }, {validator: this.matchValidator})  <--------
});

これにより、1つだけでなくグループのすべてのコントロールにアクセスできます...これには、FormGroupのcontrolsプロパティを使用してアクセスできます。検証がトリガーされると、FormGroupが提供されます。例えば:

matchValidator(group: FormGroup) {
  var valid = false;

  for (name in group.controls) {
    var val = group.controls[name].value
    (...)
  }

  if (valid) {
    return null;
  }

  return {
    mismatch: true
  };
}

詳細については、この質問を参照してください。

28

カスタムディレクティブバリデータを使用してフィールドを比較することもできます。

あなたのhtmlで:

<div>
    <label>Password</label>
    <input type="password" name="password" [ngModel]="user.password" 
        required #password="ngModel">
    <small [hidden]="password.valid || (password.pristine && !f.submitted)">
        Password is required
    </small>
</div>
<div>
    <label>Retype password</label>
    <input type="password" name="confirmPassword" [ngModel]="user.confirmPassword" 
        required validateEqual="password" #confirmPassword="ngModel">
    <small [hidden]="confirmPassword.valid ||  (confirmPassword.pristine && !f.submitted)">
        Password mismatch
    </small>
</div>

そしてあなたの指示:

import { Directive, forwardRef, Attribute } from '@angular/core';
import { Validator, AbstractControl, NG_VALIDATORS } from '@angular/forms';
@Directive({
    selector: '[validateEqual][formControlName],[validateEqual][formControl],[validateEqual][ngModel]',
    providers: [
        { provide: NG_VALIDATORS, useExisting: forwardRef(() => EqualValidator), multi: true }
    ]
})
export class EqualValidator implements Validator {
    constructor( @Attribute('validateEqual') public validateEqual: string) {}

    validate(c: AbstractControl): { [key: string]: any } {
        // self value (e.g. retype password)
        let v = c.value;

        // control value (e.g. password)
        let e = c.root.get(this.validateEqual);

        // value not equal
        if (e && v !== e.value) return {
            validateEqual: false
        }
        return null;
    }
}

Plunkrの完全なソリューションは次のとおりです。

https://plnkr.co/edit/KgjSTj7VqbWMnRdYZdxM?p=preview

13
Diego Unanue

私はこれを自分でやっていませんが、2つのパスワードフィールドで ControlGroup を作成して検証できます。コントロールには.valueChangesプロパティは観察可能であり、それらを組み合わせて、そこで同等性を確認できます。

ビクターサヴキンはAngular Air in このエピソード

4
Sasxa