Skip to content

Commit 0bcfae7

Browse files
Kevin Fahymhevery
Kevin Fahy
authored andcommitted
fix(forms): prevent event emission on enable/disable when emitEvent is false (#12366) (#21018)
Previously, the emitEvent flag was only checked when emitting on the current control. Thus, if the control was part of a hierarchy, events were emitted on the parent and the childrens. This fixes the issue by properly passing the emitEvent flag to both parent and childrens. Fixes #12366 PR Close #21018
1 parent 140e7c0 commit 0bcfae7

File tree

4 files changed

+73
-7
lines changed

4 files changed

+73
-7
lines changed

packages/forms/src/model.ts

+9-7
Original file line numberDiff line numberDiff line change
@@ -366,15 +366,16 @@ export abstract class AbstractControl {
366366
disable(opts: {onlySelf?: boolean, emitEvent?: boolean} = {}): void {
367367
(this as{status: string}).status = DISABLED;
368368
(this as{errors: ValidationErrors | null}).errors = null;
369-
this._forEachChild((control: AbstractControl) => { control.disable({onlySelf: true}); });
369+
this._forEachChild(
370+
(control: AbstractControl) => { control.disable({...opts, onlySelf: true}); });
370371
this._updateValue();
371372

372373
if (opts.emitEvent !== false) {
373374
(this.valueChanges as EventEmitter<any>).emit(this.value);
374375
(this.statusChanges as EventEmitter<string>).emit(this.status);
375376
}
376377

377-
this._updateAncestors(!!opts.onlySelf);
378+
this._updateAncestors(opts);
378379
this._onDisabledChange.forEach((changeFn) => changeFn(true));
379380
}
380381

@@ -387,16 +388,17 @@ export abstract class AbstractControl {
387388
*/
388389
enable(opts: {onlySelf?: boolean, emitEvent?: boolean} = {}): void {
389390
(this as{status: string}).status = VALID;
390-
this._forEachChild((control: AbstractControl) => { control.enable({onlySelf: true}); });
391+
this._forEachChild(
392+
(control: AbstractControl) => { control.enable({...opts, onlySelf: true}); });
391393
this.updateValueAndValidity({onlySelf: true, emitEvent: opts.emitEvent});
392394

393-
this._updateAncestors(!!opts.onlySelf);
395+
this._updateAncestors(opts);
394396
this._onDisabledChange.forEach((changeFn) => changeFn(false));
395397
}
396398

397-
private _updateAncestors(onlySelf: boolean) {
398-
if (this._parent && !onlySelf) {
399-
this._parent.updateValueAndValidity();
399+
private _updateAncestors(opts: {onlySelf?: boolean, emitEvent?: boolean}) {
400+
if (this._parent && !opts.onlySelf) {
401+
this._parent.updateValueAndValidity(opts);
400402
this._parent._updatePristine();
401403
this._parent._updateTouched();
402404
}

packages/forms/test/form_array_spec.ts

+22
Original file line numberDiff line numberDiff line change
@@ -1053,6 +1053,28 @@ import {of } from 'rxjs/observable/of';
10531053
expect(logger).toEqual(['control', 'array', 'form']);
10541054
});
10551055

1056+
it('should not emit value change events when emitEvent = false', () => {
1057+
c.valueChanges.subscribe(() => logger.push('control'));
1058+
a.valueChanges.subscribe(() => logger.push('array'));
1059+
form.valueChanges.subscribe(() => logger.push('form'));
1060+
1061+
a.disable({emitEvent: false});
1062+
expect(logger).toEqual([]);
1063+
a.enable({emitEvent: false});
1064+
expect(logger).toEqual([]);
1065+
});
1066+
1067+
it('should not emit status change events when emitEvent = false', () => {
1068+
c.statusChanges.subscribe(() => logger.push('control'));
1069+
a.statusChanges.subscribe(() => logger.push('array'));
1070+
form.statusChanges.subscribe(() => logger.push('form'));
1071+
1072+
a.disable({emitEvent: false});
1073+
expect(logger).toEqual([]);
1074+
a.enable({emitEvent: false});
1075+
expect(logger).toEqual([]);
1076+
});
1077+
10561078
});
10571079

10581080
describe('setControl()', () => {

packages/forms/test/form_control_spec.ts

+20
Original file line numberDiff line numberDiff line change
@@ -1139,6 +1139,26 @@ import {FormArray} from '@angular/forms/src/model';
11391139
expect(fn).toThrowError(`Expected validator to return Promise or Observable.`);
11401140
});
11411141

1142+
it('should not emit value change events when emitEvent = false', () => {
1143+
c.valueChanges.subscribe(() => logger.push('control'));
1144+
g.valueChanges.subscribe(() => logger.push('group'));
1145+
1146+
c.disable({emitEvent: false});
1147+
expect(logger).toEqual([]);
1148+
c.enable({emitEvent: false});
1149+
expect(logger).toEqual([]);
1150+
});
1151+
1152+
it('should not emit status change events when emitEvent = false', () => {
1153+
c.statusChanges.subscribe(() => logger.push('control'));
1154+
g.statusChanges.subscribe(() => logger.push('form'));
1155+
1156+
c.disable({emitEvent: false});
1157+
expect(logger).toEqual([]);
1158+
c.enable({emitEvent: false});
1159+
expect(logger).toEqual([]);
1160+
});
1161+
11421162
});
11431163
});
11441164
});

packages/forms/test/form_group_spec.ts

+22
Original file line numberDiff line numberDiff line change
@@ -1045,6 +1045,28 @@ import {of } from 'rxjs/observable/of';
10451045
expect(logger).toEqual(['control', 'group', 'form']);
10461046
});
10471047

1048+
it('should not emit value change events when emitEvent = false', () => {
1049+
c.valueChanges.subscribe(() => logger.push('control'));
1050+
g.valueChanges.subscribe(() => logger.push('group'));
1051+
form.valueChanges.subscribe(() => logger.push('form'));
1052+
1053+
g.disable({emitEvent: false});
1054+
expect(logger).toEqual([]);
1055+
g.enable({emitEvent: false});
1056+
expect(logger).toEqual([]);
1057+
});
1058+
1059+
it('should not emit status change events when emitEvent = false', () => {
1060+
c.statusChanges.subscribe(() => logger.push('control'));
1061+
g.statusChanges.subscribe(() => logger.push('group'));
1062+
form.statusChanges.subscribe(() => logger.push('form'));
1063+
1064+
g.disable({emitEvent: false});
1065+
expect(logger).toEqual([]);
1066+
g.enable({emitEvent: false});
1067+
expect(logger).toEqual([]);
1068+
});
1069+
10481070
});
10491071

10501072
});

0 commit comments

Comments
 (0)