【问题标题】:How to add FormControl dynamically to FormGroup in angular 5?如何在角度 5 中将 FormControl 动态添加到 FormGroup?
【发布时间】:2018-07-27 18:39:02
【问题描述】:

我正在尝试构建与 FormGroup 和 FormArray 兼容的数据表。我将通过 parentForm 组将标题详细信息和行传递给该组件。

我创建了一个小的添加按钮,点击它,我将动态添加新项目。在这种情况下,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

【问题讨论】:

    标签: angular angular-forms


    【解决方案1】:

    这是对ngOnChanges 的常见误解。 ngOnChangesPrimitive Types 配合使用效果最好,因为它们是按值传递的。

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

    一个快速而肮脏的解决方案可能是每次在父端更新对象/数组时重新实例化它。

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

    这将创建一个全新的数组,进而更改引用,并最终强制ngOnChanges 向子元素触发。

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

    【讨论】:

    • 是的,如果你看到我的代码,我已经在创建新数组并像你上面所说的那样发送。它没有帮助。
    【解决方案2】:

    您有几个问题: 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: ''
            })
        });
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-04
      • 2017-05-26
      • 1970-01-01
      • 2019-09-02
      • 1970-01-01
      相关资源
      最近更新 更多