为什么在此FormArray中无法编辑mat-form-field?

dis*_*ame 1 typescript angular-material angular

下面的表格几乎可以完成它应该做的事情,除了我无法编辑其中的任何mat-form-field内容。它们没有被禁用,只是无法编辑。

是什么原因呢?

请参阅:StackBlitz

我在StackBlitz上看不到这个示例的不同之 处。

import {Component} from '@angular/core';
import {FormBuilder, FormGroup, FormArray, FormControl} from '@angular/forms';

@Component({
  selector: 'form-field-label-example',
  templateUrl: 'form-field-label-example.html',
  styleUrls: ['form-field-label-example.css'],
})
export class FormFieldLabelExample {

  public dataList = [
    {name: 'Alice'},
    {name: 'Bob'}
  ]

  public form: FormGroup;

  constructor(private _fb: FormBuilder) {

    const formArray = this._fb.array([]);  

    for (const data of this.dataList) {
      formArray.push(
        this._fb.group({name: new FormControl(data.name)})
      );      
    }

    this.form = this._fb.group({
      offers: formArray
    });

  }

}
Run Code Online (Sandbox Code Playgroud)
<div>

  <form [formGroup]="form">

    <div formArrayName="offers" *ngFor="let data of form.controls.offers?.value; let i = index;">
      <ng-container [formGroupName]="i">
        <mat-form-field>
          <input matInput placeholder="Name" formControlName="name">
        </mat-form-field>
      </ng-container>
    </div>

  </form>

  <span *ngIf="form.dirty">DIRTY</span>

  <mat-form-field>
    <input matInput placeholder="Name">
  </mat-form-field>

</div>
Run Code Online (Sandbox Code Playgroud)

yur*_*zui 5

它确实与ngFor渲染行为有关。

更精确地说,如果ngFor中使用的数组更改了对该数组元素的引用(并且我们没有提供自定义的trackBy函数来覆盖比较),那么Angular将识别这些更改并重新渲染视图。 在此处输入图片说明

角形式通常可以触发AbstractControl.updateValueAndValidity所有控件层次的方法。

FormControl -> parent -> FormGroup -> parent -> FormArray -> parent -> FormGroup
Run Code Online (Sandbox Code Playgroud)

对于FormGroup,它将触发以下方法:

_updateValue(): void { (this as{value: any}).value = this._reduceValue(); }
Run Code Online (Sandbox Code Playgroud)

这基本上会创建一个新对象,即{name: 'Alice'},下次触发该对象时,它将用新对象覆盖当前值。

{name: 'Alice'} !== {name: 'Alice'}
Run Code Online (Sandbox Code Playgroud)

正是ngForOf指令中Angular默认识别不同。

你可能会问?

那为什么我在StackBlitz上看不到这个示例的不同之处?

在该示例中,问题仍然存在,但乍看之下看不到。

|username  password
  /\
click here(it works)

username  password
            /\
     then click here(it doesn't since the dom was rerendered)
Run Code Online (Sandbox Code Playgroud)

您的示例与上面的示例之间的区别在于,您使用了材质控件,并且触发的AbstractControl.updateValueAndValidity发生较早。

那么解决方案是什么?

1)之前提到的trackBy属性

trackByFn(index) {
  return index;
}

*ngFor="let data of form.controls.offers?.value; let i = index; trackBy: trackByFn"
Run Code Online (Sandbox Code Playgroud)

Stackblitz示例

2)分配this.form.controls.offers.value给组件属性并使用它。

arr;
...
this.arr = this.form.controls.offers.value;

*ngFor="let data of arr; let i = index;"
Run Code Online (Sandbox Code Playgroud)

Stackblitz示例