2016-03-20 12 views
17

条件付きでフォームフィールドを必要とする方法はありますか?カスタムバリデーターを作成しましたが、カスタムバリデーターに渡す条件変数は静的で、初期値のままです。更新された条件付き値を取得するために私のカスタムバリデータはどのように見えるべきですか?おそらく、カスタムバリデータの代わりにValidators.requiredでこれを行う方法がありますか?Angular 2条件付きバリデータ.required?

private foo: boolean = false; 
private bar: boolean = true; 

constructor(private _fb: FormBuilder) { 
    function conditionalRequired(...conditions: boolean[]) { 
     return (control: Control): { [s: string]: boolean } => { 
     let required: boolean = true; 
     for (var i = 0; i < conditions.length; i++) { 
      if (conditions[i] === false) { 
      required = false; 
      } 
     } 
     if (required && !control.value) { 
      return { required: true } 
     } 
     } 
    } 
    this.applyForm = _fb.group({ 
      'firstName': ['', Validators.compose([ 
      conditionalRequired(this.foo, !this.bar) 
      ])], 
      ... 
    }); 
} 

更新(2016年5月17日)

それは、これを掲示以来、長い時間がかかったが、私はそこに誰のためのControlGroupクラスで利用可能.include().exclude()メソッドを参照したいのですが誰がこの機能を作成しようとしていますか。 (docs)おそらく上記のような条件付きバリデータの使用例がありますが、これを処理するためのコントロール、コントロールグループ、およびコントロール配列の包含と除外がわかりました。あなたが望むコントロールにrequiredバリデータを設定し、それを含めたり除外したりするだけです。これが誰かを助けることを願って!

+1

は、私には;-) –

+0

を正常に見える。しかし'foo'をfalseとして表示します。バリデーターに 'console.log(conditions)'を投げると、 'foo'が実際に真であることがわかったら' [false、false] 'を返します。私は '[true、false]'を得る必要があります。私はコンストラクタの内部にあるので、条件が一度設定されているため、これが仮定されています。この現象を回避する方法はありますか? –

+1

更新プログラム内のドキュメントへのリンクが壊れています – surfbird0713

答えて

5

あなたのコメントに続き、私は潜在的な問題を見ることができます。バリデータ関数を作成する関数にプリミティブ型として条件を与えるので、最初のものを呼び出すときの値が使用されます。後に変更されても、新しい値は考慮されません。

private foo: boolean = false; 
private bar: boolean = true; 

private conditions: any = { 
    condition1: foo, 
    condition2: !bar 
}; 

constructor(private _fb: FormBuilder) { 
    function conditionalRequired(conditions: any) { 
     return (control: Control): { [s: string]: boolean } => { 
     let required: boolean = true; 
     for (var elt in conditions) { 
      var condition = conditions[elt]; 
      if (conditions === false) { 
      required = false; 
      } 
     } 
     if (required && !control.value) { 
      return { required: true }; 
     } 
     } 
    } 
    this.applyForm = _fb.group({ 
      'firstName': ['', Validators.compose([ 
      conditionalRequired(conditions) 
      ])], 
      ... 
    }); 
} 

条件パラメータを使用することができます。この方法/参照することにより、更新:

は、以下に説明するように、あなたが条件のためにオブジェクトを使用する必要があることをアーカイブします。あなたの条件を更新するには、次の手順を実行する必要があります。 https://plnkr.co/edit/bnX7p0?p=preview:ここ

updateConditions() { 
    this.conditions.condition1 = true; 
    this.conditions.condition2 = true; 
} 

はplunkrです。

編集

条件を更新する際にバリデータを実行するには、明示的に制御するupdateValueAndValidityメソッドを呼び出す必要があります。この場合は、コントロールとフォームの両方のvalid属性は適宜更新されます。

updateConditions() { 
    this.conditions.condition1 = true; 
    this.conditions.condition2 = true; 
    this.applyForm.controls.firstName.updateValueAndValidity(); 
} 
+0

残念ながら、私は同じ問題を抱えています。最初の条件は偽で、2番目は真です。 –

+0

'foo'値が変更されても値は変更されません –

+1

実際には、条件オブジェクトを更新する必要があります。私は自分の答えを更新し、働いていたプランナーを提供します... –

2

を私は私がバリデータが再利用可能にすることを可能にする関数コールバックを受け入れるバリデータを作成したが、私は見つけることができないよう他のコントロールの値が変更されたときに手動で呼び出すことなく、このバリデータでコントロールのupdateValueAndValidity()を呼び出していることを確認する良い方法です。

バリ

export class ValidationService { 
    static conditionalRequired = (isRequiredFunction: Function) => { 
     return (control: Control) => { 
      if (!control.value && isRequiredFunction()) 
      ... 

コンポーネントページ

private myControl1: Control = 
    new Control("", ValidationService.conditionalRequired(() => 
     { return this && this.model && this.model.SomeProperty === 'SomeValue' })); 

private myControl2: Control = 
    new Control("", 
    ValidationService.conditionalRequired(this.isControl2Required.bind(this))); 

isControl2Required() { 
    return someCondition; 
} 
9

私は他のバリデータと一緒に構成することができ、そのための余分なバリを書かれているので、私はそれのより一般的なバージョンを望んでいました。私はまだフォームモジュールを見始めているので、これが今までの中で最も効率的なコードであるとは思っていませんが、エッジの場合にはうまくいくとは思いませんが、それは良いスタートです。通常のユースケースで動作し、他の人にとっては良い出発点となります。

rc.4と新しいフォームモジュール用に作られたrevalidateOnChangesの部分は恐ろしいかもしれませんが(この動作を引き起こす最善の方法は不明です)、自己責任で使用してください!

バリデータは二つの引数、formGroupを与えられ、それは検証がそうでない場合は適用され、falseにある場合はtrueを返すことが期待される条件関数を取り、バリ、それを使用する方法:)

(組成物であってもよい)。これは、formGroupが更新されたときにフィールドを再検証し、現在は同じformGroup内のものだけをチェックすることができますが、修正するのは簡単なはずです。

this.formBuilder.group({ 
    vehicleType: ['', Validators.required], 
    licencePlate: [ 
     '', 
     ExtraValidators.conditional(
      group => group.controls.vehicleType.value === 'car', 
      Validators.compose([ 
       Validators.required, 
       Validators.minLength(6) 
      ]) 
     ), 
    ] 
}); 

この例では、2つのフィールド、vehicleTypeとlicencePlateがあります。 vehicleTypeが "car"の場合、条件付きステートメントは合成されたバリデータ(requiredおよびminLength)を適用します。

composeを使用して、複数の条件を同時に適用することも、適用しないこともできます。ここではもう少し複雑な例です。タイプは「車」で、国は「スウェーデン」であれば、我々ははminLengthを適用した場合、我々は必要なアプライこの場合

this.formBuilder.group({ 
    country: ['', Validators.required], 
    vehicleType: ['', Validators.required], 
    licencePlate: [ 
     '', 
     Validators.compose([ 
      ExtraValidators.conditional(
       group => group.controls.vehicleType.value === 'car', 
       Validators.required 
      ), 
      ExtraValidators.conditional(
       group => group.controls.country.value === 'sweden', 
       Validators.minLength(6) 
      ), 
     ]) 
    ] 
}); 

。 1つの条件のみが適用される場合、両方の条件が適用される場合、両方の検証が適用されます。

バリデータ自体あなたがRAMDAを使用しているか、何かあなたは多くのコードを切ることができれば、我々は、小さなオブジェクトを操作しているため、オブジェクトの比較は単純な力ずくであることを

注意。

export class ExtraValidators { 
    static conditional(conditional, validator) { 
     return function(control) { 
      revalidateOnChanges(control); 

      if (control && control._parent) { 
       if (conditional(control._parent)) { 
        return validator(control); 
       } 
      } 
     }; 
    } 
} 
function revalidateOnChanges(control): void { 
    if (control && control._parent && !control._revalidateOnChanges) { 
     control._revalidateOnChanges = true; 
     control._parent 
      .valueChanges 
      .distinctUntilChanged((a, b) => { 
       // These will always be plain objects coming from the form, do a simple comparison 
       if(a && !b || !a && b) { 
        return false; 
       } else if (a && b && Object.keys(a).length !== Object.keys(b).length) { 
        return false; 
       } else if (a && b) { 
        for (let i in a) { 
         if(a[i] !== b[i]) { 
          return false; 
         } 
        } 
       } 
       return true; 
      }) 
      .subscribe(() => { 
       control.updateValueAndValidity(); 
      }); 

     control.updateValueAndValidity(); 
    } 
    return; 
} 

:演算子をインポートすることを忘れないでください:
インポート 'rxjs /追加/オペレータ/ distinctUntilChangedを';

1

我々はコントロールを見つけた後に必要なの動的検証を設定するにはsetValidators()メソッドを使用することができます - 私は `他の場所でtrueにfoo`、カスタムバリデータを変更したとき

this.applyForm.get('firstName').setValidators(setRequired()); 

setRequired() { 
     if(1==1) { 
      return [Validators.required]; 
     } else { 
      return []; 
     } 
    }