FormControl 上的 ValueChanges 在 Form.enable 时触发,即使有 emitEvent: false
ValueChanges on FormControl triggers when Form.enable, even with emitEvent: false
FIXED: This issue was a bug that is now fixed in versions above 6.0.0 and 5.2.5, according to the GH
issue: github.com/angular/angular/issues/12366
使用 Angular (4.x) 我使用 ReactiveForms 并在我的 FormControl(“输入”)上订阅了 valueChanges,如下所示:
export class App {
version:string;
formControl = new FormControl('default', []);
form = this.fb.group({
input: this.formControl,
input2: ('',[])
});
constructor(private fb: FormBuilder) {
this.version = `Angular v${VERSION.full}`
}
ngOnInit() {
this.formControl.valueChanges.subscribe(value => doSomething(value));
}
所以现在我可以对我的 FormControl 值的变化做出反应,但我当然是从某个地方开始填写表单的值,所以我使用 form.patchValue(data)
来这样做。
由于这不是用户更改,我不想对此做出反应,所以添加标志 emitEvent: false
,例如:this.form.patchValue(data, {emitEvent: false})
.
按预期工作。
现在我有一些逻辑,当加载表单时,我将整个表单设置为禁用,this.form.disable({ emitEvent: false })
,当加载完成后,它再次将整个表单设置为启用:this.form.disable({ emitEvent: false })
但我也有逻辑,根据不同的标志将 FormControl 设置为 enabled/disabled:this.formControl.enable( {emitEvent: false});
我现在看到的问题是,当 Form
更改状态时,它会触发 FormControl.valueChanges
,即使我提供了 emitEvent: false
标志。
这是预期的行为还是错误?
我期望在提供标志时根本不会触发任何事件?
我做了一个可以在这里测试的地方:
https://plnkr.co/edit/RgyDItYtEfzlLVB6P5f3?p=preview
disable()
和 enable()
函数 (code source):
/**
* Disables the control. This means the control will be exempt from validation checks and
* excluded from the aggregate value of any parent. Its status is `DISABLED`.
*
* If the control has children, all children will be disabled to maintain the model.
* @param {?=} opts
* @return {?}
*/
AbstractControl.prototype.disable = function (opts) {
if (opts === void 0) { opts = {}; }
this._status = DISABLED;
this._errors = null;
this._forEachChild(function (control) { control.disable({ onlySelf: true }); });
this._updateValue();
if (opts.emitEvent !== false) {
this._valueChanges.emit(this._value);
this._statusChanges.emit(this._status);
}
this._updateAncestors(!!opts.onlySelf);
this._onDisabledChange.forEach(function (changeFn) { return changeFn(true); });
};
/**
* Enables the control. This means the control will be included in validation checks and
* the aggregate value of its parent. Its status is re-calculated based on its value and
* its validators.
*
* If the control has children, all children will be enabled.
* @param {?=} opts
* @return {?}
*/
AbstractControl.prototype.enable = function (opts) {
if (opts === void 0) { opts = {}; }
this._status = VALID;
this._forEachChild(function (control) { control.enable({ onlySelf: true }); });
this.updateValueAndValidity({ onlySelf: true, emitEvent: opts.emitEvent });
this._updateAncestors(!!opts.onlySelf);
this._onDisabledChange.forEach(function (changeFn) { return changeFn(false); });
};
已致电:
this._updateAncestors(!!opts.onlySelf);
它调用其父函数的 updateValueAndValidity()
函数而不带 emitEvent
标志,然后调用
this._valueChanges.emit(this._value);
这会触发表单的 valueChanges
发射器,您会在控制台中看到:
Form.valueChanges: Object { input2: null }
这是由表单触发的,而不是由 default
输入字段控制器触发的。
为了停止祖先更新,我们只需要提供额外的标志 - onlySelf: true
,它告诉只更新它自己而不是祖先。
因此,在您不想更新祖先的 disable()
或 enable()
函数的每次调用中添加此标志:
disable(){
this.form.disable({
onlySelf: true,
emitEvent: false
});
}
disableWEvent(){
this.form.disable({
onlySelf: true
});
}
enable(){
this.form.enable({
onlySelf: true,
emitEvent: false
});
}
enableWEvent(){
this.form.enable({
onlySelf: true
});
}
disableCtrl(){
this.formControl.disable({
onlySelf: true,
emitEvent: false
});
}
disableCtrlWEvent(){
this.formControl.disable({
onlySelf: true
});
}
enableCtrl(){
this.formControl.enable({
onlySelf: true,
emitEvent: false
});
}
enableCtrlWEvent(){
this.formControl.enable({
onlySelf: true
});
}
这将解决叶窗体控件(没有子控件的控件)的问题,但是这一行
this._forEachChild(function (control) { control.disable({ onlySelf: true }); });
将调用 disable
(或 enable
)函数而不传递 emitEvent: false
。它看起来像 angular 错误,因此,作为解决方法,我们可以重写这两个函数。
首先导入 AbstractControl
:
import {ReactiveFormsModule, FormBuilder, FormControl, Validators, AbstractControl} from '@angular/forms'
比覆盖两个函数:
// OVERRIDE disable and enable methods
// https://github.com/angular/angular/issues/12366
// https://github.com/angular/angular/blob/c59c390cdcd825cca67a422bc8738f7cd9ad42c5/packages/forms/src/model.ts#L318
AbstractControl.prototype.disable = function (opts) {
if (opts === void 0) { opts = {}; }
this._status = 'DISABLED';
this._errors = null;
this._forEachChild(function (control) {
control.disable(Object.assign(opts, {onlySelf: true}));
});
this._updateValue();
if (opts.emitEvent !== false) {
this._valueChanges.emit(this._value);
this._statusChanges.emit(this._status);
}
this._updateAncestors(!!opts.onlySelf);
this._onDisabledChange.forEach(function (changeFn) { return changeFn(true); });
};
AbstractControl.prototype.enable = function (opts) {
if (opts === void 0) { opts = {}; }
this._status = 'VALID';
this._forEachChild(function (control) {
control.enable(Object.assign(opts, {onlySelf: true}));
});
this.updateValueAndValidity({ onlySelf: true, emitEvent: opts.emitEvent });
this._updateAncestors(!!opts.onlySelf);
this._onDisabledChange.forEach(function (changeFn) { return changeFn(false); });
};
FIXED: This issue was a bug that is now fixed in versions above 6.0.0 and 5.2.5, according to the GH issue: github.com/angular/angular/issues/12366
使用 Angular (4.x) 我使用 ReactiveForms 并在我的 FormControl(“输入”)上订阅了 valueChanges,如下所示:
export class App {
version:string;
formControl = new FormControl('default', []);
form = this.fb.group({
input: this.formControl,
input2: ('',[])
});
constructor(private fb: FormBuilder) {
this.version = `Angular v${VERSION.full}`
}
ngOnInit() {
this.formControl.valueChanges.subscribe(value => doSomething(value));
}
所以现在我可以对我的 FormControl 值的变化做出反应,但我当然是从某个地方开始填写表单的值,所以我使用 form.patchValue(data)
来这样做。
由于这不是用户更改,我不想对此做出反应,所以添加标志 emitEvent: false
,例如:this.form.patchValue(data, {emitEvent: false})
.
按预期工作。
现在我有一些逻辑,当加载表单时,我将整个表单设置为禁用,this.form.disable({ emitEvent: false })
,当加载完成后,它再次将整个表单设置为启用:this.form.disable({ emitEvent: false })
但我也有逻辑,根据不同的标志将 FormControl 设置为 enabled/disabled:this.formControl.enable( {emitEvent: false});
我现在看到的问题是,当 Form
更改状态时,它会触发 FormControl.valueChanges
,即使我提供了 emitEvent: false
标志。
这是预期的行为还是错误? 我期望在提供标志时根本不会触发任何事件?
我做了一个可以在这里测试的地方: https://plnkr.co/edit/RgyDItYtEfzlLVB6P5f3?p=preview
disable()
和 enable()
函数 (code source):
/**
* Disables the control. This means the control will be exempt from validation checks and
* excluded from the aggregate value of any parent. Its status is `DISABLED`.
*
* If the control has children, all children will be disabled to maintain the model.
* @param {?=} opts
* @return {?}
*/
AbstractControl.prototype.disable = function (opts) {
if (opts === void 0) { opts = {}; }
this._status = DISABLED;
this._errors = null;
this._forEachChild(function (control) { control.disable({ onlySelf: true }); });
this._updateValue();
if (opts.emitEvent !== false) {
this._valueChanges.emit(this._value);
this._statusChanges.emit(this._status);
}
this._updateAncestors(!!opts.onlySelf);
this._onDisabledChange.forEach(function (changeFn) { return changeFn(true); });
};
/**
* Enables the control. This means the control will be included in validation checks and
* the aggregate value of its parent. Its status is re-calculated based on its value and
* its validators.
*
* If the control has children, all children will be enabled.
* @param {?=} opts
* @return {?}
*/
AbstractControl.prototype.enable = function (opts) {
if (opts === void 0) { opts = {}; }
this._status = VALID;
this._forEachChild(function (control) { control.enable({ onlySelf: true }); });
this.updateValueAndValidity({ onlySelf: true, emitEvent: opts.emitEvent });
this._updateAncestors(!!opts.onlySelf);
this._onDisabledChange.forEach(function (changeFn) { return changeFn(false); });
};
已致电:
this._updateAncestors(!!opts.onlySelf);
它调用其父函数的 updateValueAndValidity()
函数而不带 emitEvent
标志,然后调用
this._valueChanges.emit(this._value);
这会触发表单的 valueChanges
发射器,您会在控制台中看到:
Form.valueChanges: Object { input2: null }
这是由表单触发的,而不是由 default
输入字段控制器触发的。
为了停止祖先更新,我们只需要提供额外的标志 - onlySelf: true
,它告诉只更新它自己而不是祖先。
因此,在您不想更新祖先的 disable()
或 enable()
函数的每次调用中添加此标志:
disable(){
this.form.disable({
onlySelf: true,
emitEvent: false
});
}
disableWEvent(){
this.form.disable({
onlySelf: true
});
}
enable(){
this.form.enable({
onlySelf: true,
emitEvent: false
});
}
enableWEvent(){
this.form.enable({
onlySelf: true
});
}
disableCtrl(){
this.formControl.disable({
onlySelf: true,
emitEvent: false
});
}
disableCtrlWEvent(){
this.formControl.disable({
onlySelf: true
});
}
enableCtrl(){
this.formControl.enable({
onlySelf: true,
emitEvent: false
});
}
enableCtrlWEvent(){
this.formControl.enable({
onlySelf: true
});
}
这将解决叶窗体控件(没有子控件的控件)的问题,但是这一行
this._forEachChild(function (control) { control.disable({ onlySelf: true }); });
将调用 disable
(或 enable
)函数而不传递 emitEvent: false
。它看起来像 angular 错误,因此,作为解决方法,我们可以重写这两个函数。
首先导入 AbstractControl
:
import {ReactiveFormsModule, FormBuilder, FormControl, Validators, AbstractControl} from '@angular/forms'
比覆盖两个函数:
// OVERRIDE disable and enable methods
// https://github.com/angular/angular/issues/12366
// https://github.com/angular/angular/blob/c59c390cdcd825cca67a422bc8738f7cd9ad42c5/packages/forms/src/model.ts#L318
AbstractControl.prototype.disable = function (opts) {
if (opts === void 0) { opts = {}; }
this._status = 'DISABLED';
this._errors = null;
this._forEachChild(function (control) {
control.disable(Object.assign(opts, {onlySelf: true}));
});
this._updateValue();
if (opts.emitEvent !== false) {
this._valueChanges.emit(this._value);
this._statusChanges.emit(this._status);
}
this._updateAncestors(!!opts.onlySelf);
this._onDisabledChange.forEach(function (changeFn) { return changeFn(true); });
};
AbstractControl.prototype.enable = function (opts) {
if (opts === void 0) { opts = {}; }
this._status = 'VALID';
this._forEachChild(function (control) {
control.enable(Object.assign(opts, {onlySelf: true}));
});
this.updateValueAndValidity({ onlySelf: true, emitEvent: opts.emitEvent });
this._updateAncestors(!!opts.onlySelf);
this._onDisabledChange.forEach(function (changeFn) { return changeFn(false); });
};