在Angular
中,有一种方法可以识别动态 FormGroup
中哪个FormControl
/ FormArray
发出了valueChanges
活动吗?
我的FormArray
是动态的。它开始是空的,用户可以通过单击按钮将FormGroup
添加到FormArray
。
当valueChanges时,我需要重新验证控件。由于我不知道哪个控件发出了该事件,因此即使只更改了一个控件,我也会遍历整个FormArray
/ FormGroup
/ FormControl
并进行验证-这是每次数组更改。我该如何避免这样做?
this.myFormArray
.valueChanges
.subscribe(data => this.onValueChanged(data));
onValueChanged(data?: any): void {
// the data I receive is an entire form array.
// how can I tell which particular item emitted the event,
// so I don’t need to loop through entire array and run validation for all items.
for (let control in this.myFormArray.controls) {
// run validation on each control.
}
}
答案 0 :(得分:1)
我通过在formControl
中添加formGroup
(名为groupIndex)来跟踪索引并在valueChanges
级别而不是{ {1}}级。在formGroup
事件中,我然后可以访问存储当前索引的formArray
。
valueChanges
答案 1 :(得分:0)
您可以尝试这样的操作,但我不确定它是否可以工作
merge(...this.myFormArray.controls.map(control => control.valueChanges))
.subscribe(this will be one of your form controls' value);
答案 2 :(得分:0)
不在我的PC上进行测试,但是也许使用功能的调用者属性可能会引导您朝所需的方向前进。尽管不建议使用此属性:
此功能不是标准功能,也不在标准轨道上。请勿在面向Web的生产站点上使用它:它不适用于每个用户。实现之间也可能存在很大的不兼容性,并且将来的行为可能会发生变化。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller
一个粗略的例子:
this.myFormArray
.valueChanges
.subscribe(onValueChanged);
onValueChanged(data?: any): void {
var whoYouGonnaCall = onValueChanged.caller.caller...caller;
...
}
另一种方法是存储最后一个表单值,并使用lodash之类的属性进行比较。
var lastFormValue = this.myFormArray.value; // maybe in an init function
this.myFormArray
.valueChanges
.subscribe(onValueChanged);
onValueChanged(data?: any): void {
var diff = _.omitBy(data, function(v, k) {
return lastFormValue[k] === v;
});
this.lastFormValue = this.myFormArray.value; // Update for future requests
// diff will contain the properties if the form that changed.
...
}
答案 3 :(得分:0)
要以epsilon的答案为基础,该答案会收集valueChanges可观察变量的数组并将其合并-您还可以通过管道来传递值更改,通过映射将必要的上下文添加到更改流中。
merge(...this.formArray.controls.map((control: AbstractControl, index: number) =>
control.valueChanges.pipe(map(value => ({ rowIndex: index, value })))))
.subscribe(changes => {
console.log(changes);
});
输出:
{
rowIndex: 0
value: {
<current value of the changed object>
}
}
请注意,第一个对map的调用(在控件上)在数组上。第二个映射(在管道中)是RxJs映射。我真的很喜欢这个网站,可以帮助这些操作员直截了当,并想象这些事件流是什么样的:https://rxmarbles.com/#map
编辑: 因为我正在观看一个可由用户通过添加/删除按钮修改的FormArray,所以我添加了一个changesUnsubscribe主题,并在takeUntil中引用了该主题。这样,当列表更改时,我就可以丢弃旧的手表并设置新的手表。因此,当我从列表中添加或删除项目时,我现在调用watchForChanges()。
changesUnsubscribe = new Subject();
...
watchForChanges() {
// cleanup any prior subscriptions before re-establishing new ones
this.changesUnsubscribe.next();
merge(...this.formArray.controls.map((control: AbstractControl, index: number) =>
control.valueChanges.pipe(
takeUntil(this.changesUnsubscribe),
map(value => ({ rowIndex: index, control: control, data: value })))))
.subscribe(changes => {
this.onValueChanged(changes);
});
}
答案 4 :(得分:0)
如果有人试图将输入类型=“ number”转换为带有使用角度动态形式的控件数组的整数。
此摘要将返回已更改的实际控件。
const formArray = this.parentFormGroup.controls['obligationList'] as FormArray
formArray.controls.forEach(control => {
control.valueChanges
.debounceTime(800)
.distinctUntilChanged()
.takeUntil(this.ngUnsubscribe)
.subscribe(() => control.patchValue({amountPayable: parseInt(control.value['amountPayable'], 10)}, {emitEvent : false}))
})
答案 5 :(得分:0)
将FormArray控件绑定到模型中的数组时,可以将模型中的索引或任何其他id传递给事件处理程序:
<div *ngFor="let m of modelArr; let ix = index" formArrayName="ControlArr">
<input type="checkbox" [formControlName]="ix" (change)="my_handler($event, ix, m.id)">
</div>
和组件打字稿中的
my_handler(ev: any, ix: number, id: any): void {
console.log(ix, id);
}