angular5中如何动态添加FormControl到FormGroup?

How to add FormControl dynamically to FormGroup in angular 5?

我正在尝试构建一个与 FormGroup 和 FormArray 兼容的 data-table。我将使用 parentForm 组将 header 详细信息和行传递给此组件。

我创建了一个小的添加按钮,点击它,我将动态添加新项目。在这种情况下,UI 更新正常,但如果我打印 formGroup.value(),我只会得到传递的初始值。不是更新的 formControl。我不确定我错过了什么。

export class FormTableComponent implements OnChanges {
    @Input() headers: Array<string>;
    @Input() rows: Array<any>;
    @Input() parentFG: FormGroup;
    @Input() entriesName: string;

    get entries(): FormArray {
        return <FormArray>this.parentFG.get(this.entriesName);
    }

    constructor(private fb: FormBuilder, private cd: ChangeDetectorRef) {}

    ngOnChanges() {
        this.createFormControls();
    }

    createFormControls() {
        this.parentFG.controls[this.entriesName] = this.fb.array([]);
        this.rows.forEach(row => {
            this.entries.controls.push(this.fb.group(row));
        });
    }
}

DEMO

这是对 ngOnChanges 的常见误解。 ngOnChanges 最适合与 Primitive Types 一起使用,因为它们是按值传递的。

Javascript 中的对象和数组通过引用传递。话虽这么说,ngOnChanges 正在寻找提供给更改的输入的值。在这种情况下,对数组的引用是提供的输入,而不是数组中的值。因此,除非您将新数组传递到组件中,否则 ngOnChanges 不会触发,因此不会触发 re-rendering 您的表单。

一个快速而肮脏的解决方案可能是 re-instantiate 每次在父端更新它时 Object/Array。

this.rows = Object.assign([], newRows);

这将创建一个全新的数组,它会依次更改引用,并最终强制 ngOnChanges 触发子项。

或者,您可以以某种方式将行转换为 Observable 并在子项中订阅它。就个人而言,Observables 是处理原始类型之外的变化检测的一种更简洁的方法。 Here 是关于 Parent/Child 通过服务进行通信的文档中的一篇很棒的文章。

您有几个问题: 1. 将新行推送到 FormArray 本身以外的 FormArray 控件

this.entries.controls.push(this.fb.group(row));

应该是

this.entries.push(this.fb.group(row));

2。不要每次都创建新的 FormArray 并在调用 createFormControls() 时重新加载每一行,您可以通过 get entries() 方法

访问它

解决方案 1:

检查 entries 的长度,如果为 0,则用 rows 初始化它,否则将最后一行推入现有的 FormArray

createFormControls() {
        const keys = Object.keys(this.entries.value);
        if( keys.length === 0) {
          this.rows.forEach(row => {
              this.entries.push(this.fb.group(row));
          });
        } else {
          const row = this.rows[this.rows.length - 1];
          this.entries.push(this.fb.group(row));
        }
    }

解决方案 2:

就我个人而言,我更喜欢将 createFormArray()appendTo()popFrom() 放入父组件中。它干净且易于阅读。在这种情况下我们不需要 ChangeDetectionRef

我已将 createFormControls()form-table 组件移动到 dummy 组件并将其重命名为 createFormArray() 并稍微更改了 addNewRow(),现在一切正常正确

// create FormArray once
createFormArray() {
    const elements: any[] =[];

    this.rows.forEach(row => {
        elements.push(this.fb.group(row));
    });
    return this.fb.array(elements);
}

addNewRow() {
  const newRow =    {
            name: 'NAFFD',
            age: 12,
            place: 'TN'
        };

    this.rows.push(newRow);  // update rows

    const persons =  this.dummyForm.get('persons') as FormArray;
    persons.push(this.fb.group(newRow));  // update FormArray
}

初始化虚拟表单时,请执行以下操作:

   this.dummyForm = this.fb.group({
        persons: this.createFormArray(),
        store: this.fb.group({
            branch: '',
            code: ''
        })
    });

希望对您有所帮助,祝您编码愉快!