我想做一个函数,可以检测到Angular formGroup
实际上改变了它的值:
subscribeToFormChanges() {
const formSub = this.formGroup.valueChanges.subscribe(value => {
console.log(this.formGroup.getRawValue());
console.log(value);
if (this.formGroup.getRawValue() == value) {
console.log('equal');
} else {
console.log('not changed');
}
},
(error) => {
console.log(error)
},
() => {
this.subs.add(formSub);
})
}
为什么?- 因为有一些选择,你可以选择相同的值,它将会是 .setValue
关于 control
.
但它总是返回没有改变,即使我改变值。如何以正确的方式做?
第二种方法。
subscribeToFormChanges() {
const formSub = this.formGroup.valueChanges.pipe(startWith(null), pairwise()).subscribe(([prev, next]: [any, any]) => {
if (prev == next) {
console.log('equal');
} else {
console.log('not changed');
}
},
(error) => {
console.log(error)
},
() => {
this.subs.add(formSub);
})
}
Returns not changed all the time
你得到这些结果是因为你在比较两个不同的引用。
你可以用可视化的方式显示 表格控制树 如下:
// FG - FormGroup
// FC - FormControl
FG
/ \
FC FG
/ \
FC FC <-- <select formControlName="yourSelect">
当 FormControl.setValue
被调用(例如由于用户的改变),它的所有祖先都必须被更新。通过 updated
我的意思是更新 用户交互状态(touched
, pristine
等)。) 调用验证器 和更新 有效期.
该 updateValueAndValidity
方法负责这样的事情。它是由 FormControl.setValue
:
this._setInitialStatus();
this._updateValue();
if (this.enabled) {
this._cancelExistingSubscription();
(this as { errors: ValidationErrors | null }).errors = this._runValidator();
(this as { status: string }).status = this._calculateStatus();
if (this.status === VALID || this.status === PENDING) {
this._runAsyncValidator(opts.emitEvent);
}
}
if (opts.emitEvent !== false) {
(this.valueChanges as EventEmitter<any>).emit(this.value);
(this.statusChanges as EventEmitter<string>).emit(this.status);
}
if (this._parent && !opts.onlySelf) {
this._parent.updateValueAndValidity(opts);
}
请注意,这种方法对以下情况是一样的: FormControl
, FormArray
和 FormGroup
.
正如你所看到的,这也是一个地方。this.valueChanges
发出。这意味着根节点(例如你的 formGroup
在例子中)最终将达到,你将收到的是 累积值 从所有其他的子孙(表格控制).
您感兴趣的对象被分配给了 this.value
其解决方法为 this._updateValue()
,也就是 特定实体. జజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజ FormGroup
,这就是确定数值的方法。
_updateValue(): void {
(this as {value: any}).value = this._reduceValue();
}
_reduceValue() {
return this._reduceChildren(
{}, (acc: { [k: string]: AbstractControl }, control: AbstractControl, name: string) => {
if (control.enabled || this.disabled) {
acc[name] = control.value;
}
return acc;
});
}
从上面你可以看到 {}
,它是一个新的引用,与之前由 pairwise()
. 所以,这应该可以解释为什么你总是得到这个结果。
解决这个问题的一个方法是在之前的对象值和当前的对象值之间进行深度比较。
另一种方法是防止树被更新,除非有新的值进来。这涉及到在 leaf
级(e.g FormControl
s). 你可以创建一个 自定义控制值接入器 并在那里做逻辑。
然而,我不认为 select
会发出 change
事件,如果选择了相同的值。演示.
如果你想探索Angular Forms,我很想推荐你去看看 本文.