Angular 角度反应形式数组,更改检测覆盖形式
我使用以下内容作为我为FormArray设计表单的基础。我试图做的jist就是保持表单在页面其他地方的更改是最新的,但在此表单中切换布尔/复选框。(用户有他们选择的卡片列表,此表单显示此选择的列表) 不幸的是,Angular 角度反应形式数组,更改检测覆盖形式,angular,formarray,Angular,Formarray,我使用以下内容作为我为FormArray设计表单的基础。我试图做的jist就是保持表单在页面其他地方的更改是最新的,但在此表单中切换布尔/复选框。(用户有他们选择的卡片列表,此表单显示此选择的列表) 不幸的是,ngOnChanges似乎在不断更新表单,我的更改被覆盖。在我的构造函数中,我检测值的变化,并希望发出这些变化。但是, this.contextSummaryForm.dirty 始终为假。rebuildForm()上的断点表明该方法每秒被调用多次,因此将contextItem.Ised
ngOnChanges
似乎在不断更新表单,我的更改被覆盖。在我的构造函数中,我检测值的变化,并希望发出这些变化。但是,
this.contextSummaryForm.dirty
始终为假。rebuildForm()上的断点表明该方法每秒被调用多次,因此将contextItem.IsedetEnable更改为false将被完全覆盖。我可以阅读我的逻辑,看看为什么会发生这种情况——但我真的不明白我应该怎么做才能允许从其父组件更新contextList并允许用户在这里更新表单
构造函数和更改检测
一旦改变
总而言之:我需要一种方法来使用从输入绑定构建的FormArray,该绑定可以跟上变化,而不会快速覆盖表单。根据angular的文档 OnChanges:当指令的任何数据绑定属性发生更改时调用的生命周期挂钩 话虽如此,覆盖表单的不是变更检测,也不是onChanges钩子。作为最佳实践,我们应该只构建一次表单,并使用FormArray的方法来干扰数组 您可以使用FormArray方法和直接在数组上推送项,而不是重建表单。我假设您面临的问题是,无论数据是什么,您都在重建表单 我的意思是:认为你有两个组成部分。孩子和父母。子级负责操作数据(添加、删除),父级负责在表单上显示这些数据。尽管这样做看起来很简单,但您必须过滤掉子组件已经处理过的任何项 在您的实现中,尽量不要
在onChanges上重建表单,而是在数组上推送项
您应该将哪些项目推送到阵列?(过滤掉所有已处理的项目)
这是一种可以解决您的问题的方法
ngOnChanges(changes: SimpleChanges) {
for (let propName in changes) {
if (propName === 'contextList') {
const contextItemsToInsert =
this.contextList.filter((it: any) => !this.plans.value.map(pl => pl.id).includes(it.id));
contextItemsToInsert.forEach((x: any) => {
this.plans.push(this.fb.group({
id: x.id,
name: x.name,
isEditEnabled: x.isEditEnabled,
}))
})
// similar approach for deleted items
}
}
}
ngOnInit() {
this.createForm();
}
createForm(): void {
this.contextSummaryForm = this.fb.group({
plans: this.fb.array([this.initArrayRows()])
});
}
initArrayRows(): FormGroup {
return this.fb.group({
id: [''],
name: [''],
isEditEnabled: ['']
});
}
在这里,您可以找到一个工作示例
这不是一个完全有效的例子,但它有助于抓住问题的关键
我希望我正确地理解了您面临的问题是能否尝试比较ngOnChanges中contextList的新旧值,并且仅在它们不同时调用rebuild?很好的建议,让我今天就尝试一下,我会回来报告。我认为它缺少父组件代码。ngOnChanges被多次调用的事实可能是由于父级提供ContextList的方式。您是否可以发布当前组件的父级代码(ts | html)和html。今天上午我将尝试一下。我出去了。
createForm(): void {
this.contextSummaryForm = this.fb.group({
plans: this.fb.array([this.initArrayRows()])
});
}
initArrayRows(): FormGroup {
return this.fb.group({
id: [''],
name: [''],
isEditEnabled: [''],
});
}
ngOnChanges(changes: SimpleChanges) {
for (let propName in changes) {
if (propName === 'contextList') {
if (this.contextList) {
this.rebuildForm();
this.isLoaded = true;
}
}
}
}
rebuildForm() {
this.contextSummaryForm.reset({
});
//this.fillInPlans();
this.setPlans(this.contextList);
}
setPlans(items: ContextItem[]) {
let control = this.fb.array([]);
items.forEach(x => {
control.push(this.fb.group({
id: x.plan.id,
name: x.plan.Name,
isEditEnabled: x.isEditEnabled,
}));
});
this.contextSummaryForm.setControl('plans', control);
}
const contextItemsToInsert =
this.contextList.filter((it: any) => !this.plans.value.map(pl => pl.id).includes(it.id));
ngOnChanges(changes: SimpleChanges) {
for (let propName in changes) {
if (propName === 'contextList') {
const contextItemsToInsert =
this.contextList.filter((it: any) => !this.plans.value.map(pl => pl.id).includes(it.id));
contextItemsToInsert.forEach((x: any) => {
this.plans.push(this.fb.group({
id: x.id,
name: x.name,
isEditEnabled: x.isEditEnabled,
}))
})
// similar approach for deleted items
}
}
}
ngOnInit() {
this.createForm();
}
createForm(): void {
this.contextSummaryForm = this.fb.group({
plans: this.fb.array([this.initArrayRows()])
});
}
initArrayRows(): FormGroup {
return this.fb.group({
id: [''],
name: [''],
isEditEnabled: ['']
});
}