2017-04-24 19 views
4

FormArrayの一意性を検証するカスタムバリデータを作成しました。特定の値がすでに配列されているときにエラーを表示したい。角 - FormArrayの一意性バリデータ

問題は期待どおりに機能していないことです。

実際の動作は:

再現手順:

  • は3 "入力" 追加 - アドレス。
  • フィル入力1;
  • 入力値2を異なる値で入力します。
  • 入力1に同じ値を入力3に入力します。 (表示され、どちらの入力1でも、入力3にエラー)

期待される動作:同じ値が「Xグループ」に表示された場合は、その特定の入力がエラーを

を示してはなりません。私は4つの入力を有していると仮定すると、入力1および3

に表示されたエラー上述場合

  1. 値:スタック
  2. 値:オーバーフロー
  3. 値:スタック
  4. 値:オーバーフロー

4つの入力はすべて重複しているため、エラーを表示する必要があります。


static uniqueBy = (field: string, caseSensitive = true): ValidatorFn => { 
    return (formArray: FormArray): { [key: string]: boolean } => { 
    const controls = formArray.controls.filter(formGroup => { 
     return isPresent(formGroup.get(field).value); 
    }); 
    const uniqueObj = { uniqueBy: true }; 
    let found = false; 

    if (controls.length > 1) { 
     for (let i = 0; i < controls.length; i++) { 
     const formGroup = controls[i]; 
     const mainControl = formGroup.get(field); 
     const val = mainControl.value;  
     const mainValue = caseSensitive ? val.toLowerCase() : val; 

     controls.forEach((group, index) => { 
      if (i === index) { 
      // Same group 
      return; 
      } 

      const currControl = group.get(field); 
      const tempValue = currControl.value; 
      const currValue = caseSensitive ? tempValue.toLowerCase() : tempValue; 
      let newErrors; 

      if (mainValue === currValue) { 
      if (isBlank(currControl.errors)) { 
       newErrors = uniqueObj; 
      } else { 
       newErrors = Object.assign(currControl.errors, uniqueObj); 
      } 

      found = true; 
      } else { 
      newErrors = currControl.errors; 

      if (isPresent(newErrors)) { 
       // delete uniqueBy error 
       delete newErrors['uniqueBy']; 

       if (isBlank(newErrors)) { 
       // {} to undefined/null 
       newErrors = null; 
       } 
      } 
      } 

      // Add specific errors based on condition 
      currControl.setErrors(newErrors); 
     }); 
     } 

     if (found) { 
     // Set errors to whole formArray 
     return uniqueObj; 
     } 
    } 

    // Clean errors 
    return null; 
    }; 
} 

あなたはDEMO

がどのように私は私のバリデータを修正することができ、ここでそれを確認することができますか?私はその質問がはっきりしていることを望む。

ありがとうございます。

+0

[ui-validate](https://github.com/angular-ui/ui-validate)ライブラリ –

+2

で試すことができます。http://plnkr.co/edit/legvjz4vVQDIotr633KX?p=preview – yurzui

+0

@yurzuiデモをありがとう。それは完全に動作しているようです。私はそれを確認することができるように答えとして追加することはできますか?また、あなたが気にしないなら、それを働かせるために何をしたのかについて何らかの説明をすることができます。 –

答えて

6

あなたのコードでは、インタリーブエラーの箇所でネストされたforループが使用されています。ここで

は、検証状態は、各反復のためにどのように見えるかです:

0  [null, "{"uniqueBy":true}", null] 

    1  ["{"uniqueBy":true}", "{"uniqueBy":true}", null] 

    2  [null, "{}", null] 

http://plnkr.co/edit/MTjzQ9KiJHJ56DVAZ155?p=preview(3つのアドレスを追加し、出力を観察)

コードでは、私はループ文とドン」の一度だけ前にエラーをクリアしています下回りますもうエラーを削除しないでください。

controls.map(formGroup => formGroup.get(field)).forEach(x => x.errors && delete x.errors['uniqueBy']); 
for (let i: number = 0; i < controls.length; i++) { 
    const formGroup: FormGroup = controls[i] as FormGroup; 
    const mainControl: AbstractControl = formGroup.get(field); 
    const val: string = mainControl.value; 

    const mainValue: string = caseSensitive ? val.toLowerCase() : val; 
    controls.forEach((group: FormGroup, index: number) => { 
     if (i === index) { 
      return; 
     } 

     const currControl: any = group.get(field); 
     const tempValue: string = currControl.value; 
     const currValue: string = caseSensitive ? tempValue.toLowerCase() : tempValue; 
     let newErrors: any; 

     if (mainValue === currValue) { 
      if (isBlank(currControl.errors)) { 
       newErrors = uniqueObj; 
      } else { 
       newErrors = Object.assign(currControl.errors, uniqueObj); 
      } 
      currControl.setErrors(newErrors); 
      find = true; 
     } 
    }); 
} 

Plunker Example

+0

ありがとう:) –

0

私はちょうど新しい答えとしてこれを入れているので、私はコメントを追加することができませんでした。重複した値のフィールドを修正した後、フォームが無効のままであったため、yurzuiのプランナーを少し修正しました。 どうyurzuiのplunkerでエラーを再現するには: 1°の値と、通りに記入 2°正しく名前を記入「X」 3度に2つ目の通り変更 4°「X」の通りの値を使用して新しいアドレスを追加します。 'x'以外の文字

最初の 'street' FormControlがnullではなく '{}'に設定されているため、フォームは無効です。私はちょうどdev_054は彼のオリジナルのポストでそれをやったことに気づいたが、とにかく、ここで変更でplunkerです:http://plnkr.co/edit/ejx8R3HKbu2zXRw41oKc?p=preview

コードがした

controls.map(formGroup => formGroup.get(field)).forEach(x => x.errors && delete x.errors['uniqueBy']); 

コードは以下のようになります。では

controls.map(formGroup => formGroup.get(field)).forEach(x => { 
     if(x.errors){ 
     delete x.errors['unique-by']; 
     if(isBlank(x.errors)){ 
      x.setErrors(null); 
     } 
     } 
    }); 

plunker私はまた、caseSensitiveパラメータが解釈された方法を切り替えました。 caseSentiveがtrueの場合、2つのフィールドに値 'street'と 'STREET'がある場合、エラーは表示されません。それはcaseSentiveが偽である場合それはなります。 私はこれが役立つことを願っています。

dev_054とyurzuiに大きな感謝をしてくれた皆さん、とても素敵なバリデーターを作ってくれました。