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

时间:2019-05-10 17:33:10

标签: angular typescript angular-material

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

这是什么原因?

请参阅:StackBlitz

我看不到StackBlitz与this example有什么区别。

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
    });

  }

}
<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>

2 个答案:

答案 0 :(得分:4)

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

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

对于所有控件层次结构,角形式通常可以触发AbstractControl.updateValueAndValidity方法。

FormControl -> parent -> FormGroup -> parent -> FormArray -> parent -> FormGroup

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

_updateValue(): void { (this as{value: any}).value = this._reduceValue(); }

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

{name: 'Alice'} !== {name: 'Alice'}

这正是ngForOf指令中可以识别的Angular默认值不同。

您可能会问?

那为什么我在StackBlitz上看不到this example有什么区别?

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

|username  password
  /\
click here(it works)

username  password
            /\
     then click here(it doesn't since the dom was rerendered)

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

那有什么解决方案?

1)之前提到的trackBy属性

trackByFn(index) {
  return index;
}

*ngFor="let data of form.controls.offers?.value; let i = index; trackBy: trackByFn"

Stackblitz Example

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

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

*ngFor="let data of arr; let i = index;"

Stackblitz Example

答案 1 :(得分:0)

我刚刚更改了您的代码,现在可以使用了。 请检查一下。如果这不是您真正想要的,也许您可​​以找到一些解决问题的办法。

https://stackblitz.com/edit/angular-ckpey4-bxiidz?file=app/form-field-label-example.html