首页 文章

如何在角度5中动态地将FormControl添加到FormGroup?

提问于
浏览
2

我正在尝试构建一个与FormGroup和FormArray兼容的数据表 . 我将使用parentForm组将 Headers 详细信息和行传递给此组件 .

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

2 回答

  • 0

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

    enter image description here

    希望它有帮助,编码愉快!

  • 2

    这是关于 ngOnChanges 的常见误解 . ngOnChanges 最适合Primitive Types,因为它们是按值传递的 .

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

    一个快速而肮脏的解决方案可能是每次在Parent端更新它时重新实例化Object / Array .

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

    这将创建一个全新的数组,它应该反过来更改引用,并最终强制 ngOnChanges 触发孩子 .

    或者,您可以以某种方式将您的行转换为 Observable 并在子项内订阅它 . 就个人而言,Observables是一种更清晰的方式来处理原始类型之外的变化检测 . Here是关于通过服务进行父/子通信的文档的精彩文章 .

相关问题