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));
});
}
}
这是对 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: ''
})
});
希望对您有所帮助,祝您编码愉快!
我正在尝试构建一个与 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));
});
}
}
这是对 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: ''
})
});
希望对您有所帮助,祝您编码愉快!