如何验证 angular 中的 formarray?

How to validate formarray in angular?

我正在使用 editable 和 formarray。 我的模型:

class Book {
  id: number;
  name: string;
  active: boolean;
}

所有图书:

[
 {id: 1, name: 'book1', active: true},
 {id: 2, name: 'book2', active: true},
 {id: 3, name: 'book3', active: true},
]

代码片段:

allBooks: Book[];
bookFg: FormGroup;

ngOnInit() {
  this.bookFg = this.fb.group({
    arrayForm: this.fb.array(allBooks.map(book => {
      id: [book.id],
      name: [book.name],
      active: [book.active]
    }))
  });
}

我必须验证书名,名称是必需的并且是唯一的。 html 片段:

<div class="data-container" [formGroup]="bookFg">
        <p-table id="resultTable" [columns]="cols" [value]="labelForm.get('arrayForm').controls" formArrayName="arrayForm" dataKey="value.id" scrollable="true" [resizableColumns]="true" scrollHeight="415px" selectionMode="single"
        [selection]="selected" (onRowSelect)="onRowSelect($event.data)">
          <ng-template pTemplate="header" let-columns>
            ...
            ...
            ...
          </ng-template>
          <ng-template pTemplate="body" let-rowData let-rowIndex="rowIndex">

            <tr [pSelectableRow]="rowData" [formGroupName]="rowIndex">
              <td>
                  <div class="text-center">
                    <input pInputText type="checkbox" formControlName="active">
                  </div>
              </td>
              <td pEditableColumn>
                  <p-cellEditor>
                      <ng-template pTemplate="input">
                          <input (focus)="onFocusEvent(rowIndex)" (blur)="onBlurEvent()" pInputText type="text" formControlName="name">
                      </ng-template>
                      <ng-template pTemplate="output">
                          {{rowData.get('name').value}}
                      </ng-template>
                  </p-cellEditor>
              </td>

            </tr>
          </ng-template>
        </p-table>
    </div>

在这个editable table中,每一行都是formgroup。编辑名称列后,将保存此行。问题是如何验证?在我的例子中,一次只保存一行。那么我应该验证所有的 formarray 还是只验证那个 formarray 中的一个 formgroup?以及如何?

你可以选择不要一个大表格,保存时将表格组传递给该行,并在保存前检查该行是否有效。这将使您的代码更易于理解。保存后,您需要使用 this.form.markAsPristine().

重置该表单

您也可以通过将行的表单组传递到保存方法来使用大表单实现此目的。

只是数组上的 customValidator。无论如何,您的代码中存在类型错误,请查看 stackblitz

ngOnInit() {
    this.bookFg = this.fb.group({
      arrayForm: this.fb.array(
        this.allBooks.map(book =>
          this.fb.group({
            id: [book.id],
            name: [book.name],
            active: [book.active]
          })
        )
      )
    });
  }

  myCustomValidator() {
    return (formArray: FormArray) => {
      let valid: boolean = true;
      formArray.value.forEach((x, index) => {
        if (formArray.value.findIndex(y => y.name == x.name) != index)
          valid = false;
      });
      return valid ? null : { error: "Names must be unique" };
    };
  }

Update 您也可以只为字段 "name"

创建验证器
myCustomValidatorName(index) {
    return (formControl: FormControl) => {
      let valid: boolean = true;
      if (index) {
        const formArray =
          formControl.parent && formControl.parent.parent
            ? (formControl.parent.parent as FormArray)
            : null;
        if (formArray) {
          console.log(formControl.value);
          formArray.value.forEach((x, i) => {
            if (x.name == formControl.value && index>i) valid = false;
          });
        }
      }
      return valid ? null : { error: "Names must be inique" };
    };
  }

你创建的表单就像

ngOnInit() {
    this.bookFg = this.fb.group({
      arrayForm: this.fb.array(
        this.allBooks.map((book, i) =>
          this.fb.group({
            id: new FormControl(book.id),
            name: new FormControl(book.name, this.myCustomValidatorName(i)),
            active: new FormControl(book.active)
          })
        ),
        this.myCustomValidator()
      )
    });
  }

但问题是,改名字的时候,不检查别人的名字。所以你必须创建一个函数

checkArray(index) {
    (this.bookFg.get("arrayForm") as FormArray).controls.forEach((x, i) => {
      if (i != index) x.get("name").updateValueAndValidity();
    });
  }

并调用编辑的(输入)-或订阅 valuesChange-

  <input formControlName="name" (input)="checkArray(i)">

更新如何在提交或模糊时验证

为了在提交或模糊时验证,我们需要使用 formGroup 和 FormControl 的构造函数创建表单,而不是使用 FormBuilder 在 new FormGroup (*) 的末尾添加 {updateOn:'blur'}{updateOn:'submit'}这种情况下在输入中使用 (blur)

this.bookFg = new FormGroup({
      arrayForm: new FormArray(
        this.allBooks.map((book, i) =>
          this.fb.group({
            id: new FormControl(book.id),
            name: new FormControl(book.name,this.myCustomValidatorName(i)),
            active: new FormControl(book.active)
          })
        ),
        this.myCustomValidator()
      )
    },{updateOn: 'blur'}); //<--this