2017-04-24 38 views
4

我創建了一個自定義驗證程序來驗證我的FormArray中的唯一性。當特定值已經在數組中時,我想顯示錯誤。FormArray中的角度 - 唯一性驗證程序

問題是它沒有按預期工作。

實際行爲:

重現步驟:

  • 添加3 「投入」 - 地址;
  • 填入輸入1;
  • 用不同的值填充輸入2;
  • 用輸入1的相同值填充輸入3; (出現任何錯誤,無論是在輸入1,也不在輸入3)

預期行爲

如果相同的值出現在「X基團」,其具體的輸入必須顯示錯誤。

在錯誤上述應該出現在輸入1和3

假設我有4個輸入的情況下:

  1. 值:堆
  2. 值:溢出
  3. 值:堆棧
  4. value:溢出

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(添加三個地址,並觀察輸出)

在下面的代碼我只有過一次清除錯誤的循環語句和Don」不再刪除錯誤。

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的闖入者中重現錯誤: 1°正確填寫姓名 2°填寫價值爲'x'的街道 3°添加街道值爲'x'的新地址 4°將第二條街道更改爲'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爲真,如果兩個字段的值爲「街道」和「街道」,則不會顯示錯誤。它會,如果caseSentive是虛假的。 我希望這可以幫助。

非常感謝dev_054和yurzui,你們做了一個非常好的驗證器,並且讓我獲得了很多時間。