剑道:将顶部的 FormGroup 插入 FormArray
Posted
技术标签:
【中文标题】剑道:将顶部的 FormGroup 插入 FormArray【英文标题】:Kendo : Insert a FormGroup at a top into a FormArray 【发布时间】:2020-01-26 01:37:37 【问题描述】:问题陈述:
在下面的 stackblitz 演示中,我可以在单击 Add
按钮并从一个控件触发 (blur)
事件以更新另一个共享相同控件的值时,在网格的开头动态插入 FormGroup
rowIndex
。现在的问题是,如果我插入多个formGroups
并在任何新添加的FormGroups
上触发(blur)
事件,它会更新其他控件的值以及具有不同的rowIndex
。
重现问题的步骤:
打开下面的演示链接。 通过单击“添加”按钮添加多行(2 行)。 在新添加的第二行的名称字段中输入值并聚焦。 它更新两个新添加的行中的年龄字段,而不是仅在第二行中。Stackblitz 演示: https://stackblitz.com/edit/angular-oitz5j-4uezqr
要求:
标记特定行的任何名称字段,同一行的年龄字段应显示随机数,而不会影响其他行。
到目前为止我尝试了什么?
尝试使用 Array unshift() 方法但出现错误
类型“FormArray”上不存在属性“unshift”
尝试使用FormArray.insert() 方法。如果我们想在特定索引处添加FormGroup
,它将起作用。但它无法在FormArray
顶部动态插入多个FormGroups
。
更新:上述问题在没有 Kendo Grid 的情况下运行良好。请查看以下演示。
演示: https://stackblitz.com/edit/angular-oitz5j-2a31gs
github/*** 中的相关问题:
https://github.com/angular/angular/issues/16322
Angular - Form Array push specific index
注意:如果我们要在 Grid 的末尾添加控件,它会像冠军一样工作。请检查下面的演示,它在最后添加控件时效果很好。
演示: https://stackblitz.com/edit/angular-oitz5j-aszrjq
【问题讨论】:
对于第一个演示,当我尝试复制这些步骤时,我可以在控制台中看到错误。 stackblitz 有什么变化吗? @PankajParkar 很抱歉这个错误。我纠正了这一点。可以请您现在检查吗 这是一个有趣的部分:尝试调用函数addNewRow()
两次以添加行和onFocusOut(1)
以模拟预期的行为,一切正常!
试图解决问题:每次数据更改时,您都在创建新的表单组,每次按下添加按钮时,您都会在 addNewRow()
函数和 subscription
中插入新组.
@SachinGupta 我正在更新数据源和控件。您可以在没有剑道的情况下查看演示,并且运行良好。
【参考方案1】:
对于那些想要在 FormArray 中动态插入元素的人,请使用索引为 0 的 Insert。
this.formName.controls.FieldNameArray.insert(0,[...])
https://angular.io/api/forms/FormArray#insert.
【讨论】:
【参考方案2】:为什么我的代码不起作用?
这根本不是剑道问题。每次触发 view
observable 时,您的整个表单都已创建完毕。因此,当您添加一行时,您基本上将添加到createForm
中的items
以及触发view
可观察对象(通过调用updateGridData
),这反过来又添加到@987654329 中的items
@。 Telerik 似乎在做后者,如example 所示,所以我们根本不需要在addNewRow
中将insert
转换为items
。相反,只需更新gridData
,然后调用updateGridData
。
解决方案
您的代码中只有两个问题。第一个在您的view
订阅块中。您使用的代码基本上只是在之前的 items
之上推送而不是替换它们。所以我们需要在这里重新初始化items
FormArray
。
this.view.subscribe(r =>
this.createForm.setControl('items', new FormArray([]));
r.data.forEach((i) =>
const newRow = new FormGroup(
name: new FormControl(i.name),
age: new FormControl(i.age)
);
(this.createForm.get("items") as FormArray).push(newRow);
);
);
您可以使用map
重写此代码,如下所示。
this.view.subscribe(r =>
this.createForm.setControl('items', new FormArray(r.data.map(item =>
new FormGroup(
name: new FormControl(item.name),
age: new FormControl(item.age),
)
)));
);
现在您需要做的就是在添加新行时分配gridData
。我们需要从createForm
获取用户输入的数据,因为gridData
没有绑定到任何地方,也不会包含用户输入的数据。由于view
subscribe 块已经负责声明createForm
,因此无需对此处的表单执行任何操作。
addNewRow()
const blankRow =
name: "",
age: ""
;
this.gridData = [blankRow, ...this.createForm.get('items').value];
const data: GridDataResult = data: this.gridData, total: this.gridData.length ;
this.editService.updateGridData(data);
网格现在应该可以工作了。
Forked StackBlitz
注意:将新行推到网格末尾的示例有效的原因是您只在ngOnInit
的开头声明了一次createForm
。然后手动将gridData
和insert
更新为items
。这里没有updateGridData
触发view
重新创建createForm
。如果有,即使这样也不会按预期工作。
【讨论】:
您根据我们的要求建议的解决方案存在一个问题。每次我们添加一个新的表单组时都重新启动 FormArray - 假设我们已经有 n 个 FormGroup 并在控件上进行了一些自定义验证。因此,如果我们再次初始化整个 FormArray 只是为了添加一个新的 FormGroup 将重置所有现有的验证,并可能导致性能问题再次使用 n 个 FormGroup 重新创建整个 FormArray。请提出建议。【参考方案3】:我是如何开始调试的:
我并不是说这并不奇怪,但是当您调用该方法 FormArray.insert
时,它会插入现有 formArray 的副本并与当前状态连接。我添加了 console.log(formArray.controls)
并检查它是否呈指数增长,这意味着每次插入都会添加一个快照。
这让我发现您订阅了 view
Observable,并且每当它发生变化时,您都会使用现有列表推送网格中的所有项目。
如何解决:
第 1 步:在您的 addRow 方法中删除 formGroup 的创建并插入到数组中,因为它已在您的 view.subscribe 方法中处理
addNewRow()
...
/*
<--- remove the creation of formgroup and adding to formarray taken care in next step --->
if (this.createForm)
(this.createForm.get("items") as FormArray).insert(2, newRow);
*/
第 2 步:在您的 view.subscribe 方法中从 push 更改为 insert。所以初始项目也将被插入而不是推送
this.view.subscribe(r =>
r.data.forEach((data, i) => //<-- Added index of the array
const newRow = new FormGroup(
name: new FormControl(data.name),
age: new FormControl(data.age),
);
if (this.createForm)
(this.createForm.get("items") as FormArray).insert(i, newRow);//<--changed to insert
);
);
第 3 步现在您要取消换档
addNewRow()
const blankRow =
name: "",
age: "",
;
this.gridData.unshift(blankRow); //<-- you do it here.
const data: GridDataResult = data: this.gridData, total: this.gridData.length,
this.editService.updateGridData(data);
更新 Stackblitz 供您参考:https://stackblitz.com/edit/angular-oitz5j-ulhs4k
【讨论】:
这里不能使用unshift
。请注意,如果您在 StackBlitz 中添加一行,在其中输入数据,然后再添加另一行,您刚刚输入的数据将消失。
您根据我们的要求建议的解决方案存在一个问题。每次我们添加一个新的表单组时都重新启动 FormArray - 假设我们已经有 n 个 FormGroup 并在控件上进行了一些自定义验证。因此,如果我们再次初始化整个 FormArray 只是为了添加一个新的 FormGroup 将重置所有现有的验证,并可能导致性能问题再次使用 n 个 FormGroup 重新创建整个 FormArray。请提出建议。【参考方案4】:
问题是剑道网格。您一遍又一遍地踩在其数据源的索引 0 上
谁知道他会在内部做什么来显示数据。但事实是它没有使用表单数组值。如果您从 kendo 网格数组中取出将正常工作,或者如果您在 onFocusOut 方法的末尾添加控制台日志console.log(this.createForm.get("items").value);
,您将看到 formArray 的值很好。
如果您需要使用是或是剑道网格。阅读以下文档:
https://www.telerik.com/kendo-angular-ui/components/grid/editing/editing-reactive-forms/
我看到的示例表明您无法在外部处理表单。您需要使用剑道网格提供的方法。因为剑道网格并没有真正显示 fromArray 值
【讨论】:
是的,问题出在 Kendo Grid 上,但是如果我们在 FormArray 的末尾推送 FormGroup,它的工作正常。唯一的问题是在顶部添加。 是的。因为当您在不存在的索引中添加元素时,剑道网格没有任何与该索引映射的项目。当你步进索引 0 时会破坏剑道网格的内部映射。请参阅示例。 Kendo 使用内部对象向数据源添加新项目。以上是关于剑道:将顶部的 FormGroup 插入 FormArray的主要内容,如果未能解决你的问题,请参考以下文章
无法绑定到“formGroup”,因为它不是“form”的已知属性
无法绑定到“formGroup”,因为它不是登录组件中“form”的已知属性
无法绑定到“formGroup”,因为它不是 Angular 中“form”的已知属性