feat(forms): add emitEvent
option for AbstractControl-based class methods (#31031)
This commit adds the `emitEvent` option to the following FormArray and FormGroup methods: * FormGroup.addControl * FormGroup.removeControl * FormGroup.setControl * FormArray.push * FormArray.insert * FormArray.removeAt * FormArray.setControl * FormArray.clear This option can be used to prevent an event from being emitted when adding or removing controls. BREAKING CHANGE: The `emitEvent` option was added to the following `FormArray` and `FormGroup` methods: * FormGroup.addControl * FormGroup.removeControl * FormGroup.setControl * FormArray.push * FormArray.insert * FormArray.removeAt * FormArray.setControl * FormArray.clear If your app has custom classes that extend `FormArray` or `FormGroup` classes and override the above-mentioned methods, you may need to update your implementation to take the new options into account and make sure that overrides are compatible from a types perspective. Closes #29662. PR Close #31031
This commit is contained in:
parent
645c2ef973
commit
4ec045e12b
32
goldens/public-api/forms/forms.d.ts
vendored
32
goldens/public-api/forms/forms.d.ts
vendored
@ -172,20 +172,30 @@ export declare class FormArray extends AbstractControl {
|
||||
get length(): number;
|
||||
constructor(controls: AbstractControl[], validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null, asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null);
|
||||
at(index: number): AbstractControl;
|
||||
clear(): void;
|
||||
clear(options?: {
|
||||
emitEvent?: boolean;
|
||||
}): void;
|
||||
getRawValue(): any[];
|
||||
insert(index: number, control: AbstractControl): void;
|
||||
insert(index: number, control: AbstractControl, options?: {
|
||||
emitEvent?: boolean;
|
||||
}): void;
|
||||
patchValue(value: any[], options?: {
|
||||
onlySelf?: boolean;
|
||||
emitEvent?: boolean;
|
||||
}): void;
|
||||
push(control: AbstractControl): void;
|
||||
removeAt(index: number): void;
|
||||
push(control: AbstractControl, options?: {
|
||||
emitEvent?: boolean;
|
||||
}): void;
|
||||
removeAt(index: number, options?: {
|
||||
emitEvent?: boolean;
|
||||
}): void;
|
||||
reset(value?: any, options?: {
|
||||
onlySelf?: boolean;
|
||||
emitEvent?: boolean;
|
||||
}): void;
|
||||
setControl(index: number, control: AbstractControl): void;
|
||||
setControl(index: number, control: AbstractControl, options?: {
|
||||
emitEvent?: boolean;
|
||||
}): void;
|
||||
setValue(value: any[], options?: {
|
||||
onlySelf?: boolean;
|
||||
emitEvent?: boolean;
|
||||
@ -272,7 +282,9 @@ export declare class FormGroup extends AbstractControl {
|
||||
constructor(controls: {
|
||||
[key: string]: AbstractControl;
|
||||
}, validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null, asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[] | null);
|
||||
addControl(name: string, control: AbstractControl): void;
|
||||
addControl(name: string, control: AbstractControl, options?: {
|
||||
emitEvent?: boolean;
|
||||
}): void;
|
||||
contains(controlName: string): boolean;
|
||||
getRawValue(): any;
|
||||
patchValue(value: {
|
||||
@ -282,12 +294,16 @@ export declare class FormGroup extends AbstractControl {
|
||||
emitEvent?: boolean;
|
||||
}): void;
|
||||
registerControl(name: string, control: AbstractControl): AbstractControl;
|
||||
removeControl(name: string): void;
|
||||
removeControl(name: string, options?: {
|
||||
emitEvent?: boolean;
|
||||
}): void;
|
||||
reset(value?: any, options?: {
|
||||
onlySelf?: boolean;
|
||||
emitEvent?: boolean;
|
||||
}): void;
|
||||
setControl(name: string, control: AbstractControl): void;
|
||||
setControl(name: string, control: AbstractControl, options?: {
|
||||
emitEvent?: boolean;
|
||||
}): void;
|
||||
setValue(value: {
|
||||
[key: string]: any;
|
||||
}, options?: {
|
||||
|
@ -1450,22 +1450,34 @@ export class FormGroup extends AbstractControl {
|
||||
*
|
||||
* @param name The control name to add to the collection
|
||||
* @param control Provides the control for the given name
|
||||
* @param options Specifies whether this FormGroup instance should emit events after a new
|
||||
* control is added.
|
||||
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
||||
* `valueChanges` observables emit events with the latest status and value when the control is
|
||||
* added. When false, no events are emitted.
|
||||
*/
|
||||
addControl(name: string, control: AbstractControl): void {
|
||||
addControl(name: string, control: AbstractControl, options: {emitEvent?: boolean} = {}): void {
|
||||
this.registerControl(name, control);
|
||||
this.updateValueAndValidity();
|
||||
this.updateValueAndValidity({emitEvent: options.emitEvent});
|
||||
this._onCollectionChange();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a control from this group.
|
||||
*
|
||||
* This method also updates the value and validity of the control.
|
||||
*
|
||||
* @param name The control name to remove from the collection
|
||||
* @param options Specifies whether this FormGroup instance should emit events after a
|
||||
* control is removed.
|
||||
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
||||
* `valueChanges` observables emit events with the latest status and value when the control is
|
||||
* removed. When false, no events are emitted.
|
||||
*/
|
||||
removeControl(name: string): void {
|
||||
removeControl(name: string, options: {emitEvent?: boolean} = {}): void {
|
||||
if (this.controls[name]) this.controls[name]._registerOnCollectionChange(() => {});
|
||||
delete (this.controls[name]);
|
||||
this.updateValueAndValidity();
|
||||
this.updateValueAndValidity({emitEvent: options.emitEvent});
|
||||
this._onCollectionChange();
|
||||
}
|
||||
|
||||
@ -1474,12 +1486,17 @@ export class FormGroup extends AbstractControl {
|
||||
*
|
||||
* @param name The control name to replace in the collection
|
||||
* @param control Provides the control for the given name
|
||||
* @param options Specifies whether this FormGroup instance should emit events after an
|
||||
* existing control is replaced.
|
||||
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
||||
* `valueChanges` observables emit events with the latest status and value when the control is
|
||||
* replaced with a new one. When false, no events are emitted.
|
||||
*/
|
||||
setControl(name: string, control: AbstractControl): void {
|
||||
setControl(name: string, control: AbstractControl, options: {emitEvent?: boolean} = {}): void {
|
||||
if (this.controls[name]) this.controls[name]._registerOnCollectionChange(() => {});
|
||||
delete (this.controls[name]);
|
||||
if (control) this.registerControl(name, control);
|
||||
this.updateValueAndValidity();
|
||||
this.updateValueAndValidity({emitEvent: options.emitEvent});
|
||||
this._onCollectionChange();
|
||||
}
|
||||
|
||||
@ -1876,11 +1893,16 @@ export class FormArray extends AbstractControl {
|
||||
* Insert a new `AbstractControl` at the end of the array.
|
||||
*
|
||||
* @param control Form control to be inserted
|
||||
* @param options Specifies whether this FormArray instance should emit events after a new
|
||||
* control is added.
|
||||
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
||||
* `valueChanges` observables emit events with the latest status and value when the control is
|
||||
* inserted. When false, no events are emitted.
|
||||
*/
|
||||
push(control: AbstractControl): void {
|
||||
push(control: AbstractControl, options: {emitEvent?: boolean} = {}): void {
|
||||
this.controls.push(control);
|
||||
this._registerControl(control);
|
||||
this.updateValueAndValidity();
|
||||
this.updateValueAndValidity({emitEvent: options.emitEvent});
|
||||
this._onCollectionChange();
|
||||
}
|
||||
|
||||
@ -1889,23 +1911,33 @@ export class FormArray extends AbstractControl {
|
||||
*
|
||||
* @param index Index in the array to insert the control
|
||||
* @param control Form control to be inserted
|
||||
* @param options Specifies whether this FormArray instance should emit events after a new
|
||||
* control is inserted.
|
||||
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
||||
* `valueChanges` observables emit events with the latest status and value when the control is
|
||||
* inserted. When false, no events are emitted.
|
||||
*/
|
||||
insert(index: number, control: AbstractControl): void {
|
||||
insert(index: number, control: AbstractControl, options: {emitEvent?: boolean} = {}): void {
|
||||
this.controls.splice(index, 0, control);
|
||||
|
||||
this._registerControl(control);
|
||||
this.updateValueAndValidity();
|
||||
this.updateValueAndValidity({emitEvent: options.emitEvent});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the control at the given `index` in the array.
|
||||
*
|
||||
* @param index Index in the array to remove the control
|
||||
* @param options Specifies whether this FormArray instance should emit events after a
|
||||
* control is removed.
|
||||
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
||||
* `valueChanges` observables emit events with the latest status and value when the control is
|
||||
* removed. When false, no events are emitted.
|
||||
*/
|
||||
removeAt(index: number): void {
|
||||
removeAt(index: number, options: {emitEvent?: boolean} = {}): void {
|
||||
if (this.controls[index]) this.controls[index]._registerOnCollectionChange(() => {});
|
||||
this.controls.splice(index, 1);
|
||||
this.updateValueAndValidity();
|
||||
this.updateValueAndValidity({emitEvent: options.emitEvent});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1913,8 +1945,13 @@ export class FormArray extends AbstractControl {
|
||||
*
|
||||
* @param index Index in the array to replace the control
|
||||
* @param control The `AbstractControl` control to replace the existing control
|
||||
* @param options Specifies whether this FormArray instance should emit events after an
|
||||
* existing control is replaced with a new one.
|
||||
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
||||
* `valueChanges` observables emit events with the latest status and value when the control is
|
||||
* replaced with a new one. When false, no events are emitted.
|
||||
*/
|
||||
setControl(index: number, control: AbstractControl): void {
|
||||
setControl(index: number, control: AbstractControl, options: {emitEvent?: boolean} = {}): void {
|
||||
if (this.controls[index]) this.controls[index]._registerOnCollectionChange(() => {});
|
||||
this.controls.splice(index, 1);
|
||||
|
||||
@ -1923,7 +1960,7 @@ export class FormArray extends AbstractControl {
|
||||
this._registerControl(control);
|
||||
}
|
||||
|
||||
this.updateValueAndValidity();
|
||||
this.updateValueAndValidity({emitEvent: options.emitEvent});
|
||||
this._onCollectionChange();
|
||||
}
|
||||
|
||||
@ -2095,6 +2132,12 @@ export class FormArray extends AbstractControl {
|
||||
/**
|
||||
* Remove all controls in the `FormArray`.
|
||||
*
|
||||
* @param options Specifies whether this FormArray instance should emit events after all
|
||||
* controls are removed.
|
||||
* * `emitEvent`: When true or not supplied (the default), both the `statusChanges` and
|
||||
* `valueChanges` observables emit events with the latest status and value when all controls
|
||||
* in this FormArray instance are removed. When false, no events are emitted.
|
||||
*
|
||||
* @usageNotes
|
||||
* ### Remove all elements from a FormArray
|
||||
*
|
||||
@ -2122,11 +2165,11 @@ export class FormArray extends AbstractControl {
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
clear(): void {
|
||||
clear(options: {emitEvent?: boolean} = {}): void {
|
||||
if (this.controls.length < 1) return;
|
||||
this._forEachChild((control: AbstractControl) => control._registerOnCollectionChange(() => {}));
|
||||
this.controls.splice(0);
|
||||
this.updateValueAndValidity();
|
||||
this.updateValueAndValidity({emitEvent: options.emitEvent});
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
@ -18,12 +18,14 @@ describe('FormArray', () => {
|
||||
describe('adding/removing', () => {
|
||||
let a: FormArray;
|
||||
let c1: FormControl, c2: FormControl, c3: FormControl;
|
||||
let logger: string[];
|
||||
|
||||
beforeEach(() => {
|
||||
a = new FormArray([]);
|
||||
c1 = new FormControl(1);
|
||||
c2 = new FormControl(2);
|
||||
c3 = new FormControl(3);
|
||||
logger = [];
|
||||
});
|
||||
|
||||
it('should support pushing', () => {
|
||||
@ -64,6 +66,100 @@ describe('FormArray', () => {
|
||||
|
||||
expect(a.controls).toEqual([c1, c2, c3]);
|
||||
});
|
||||
|
||||
it('should not emit events when calling `FormArray.push` with `emitEvent: false`', () => {
|
||||
a.valueChanges.subscribe(() => logger.push('value change'));
|
||||
a.statusChanges.subscribe(() => logger.push('status change'));
|
||||
|
||||
a.push(c1, {emitEvent: false});
|
||||
|
||||
expect(a.length).toEqual(1);
|
||||
expect(a.controls).toEqual([c1]);
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
|
||||
it('should not emit events when calling `FormArray.removeAt` with `emitEvent: false`', () => {
|
||||
a.push(c1);
|
||||
a.push(c2);
|
||||
a.push(c3);
|
||||
|
||||
a.valueChanges.subscribe(() => logger.push('value change'));
|
||||
a.statusChanges.subscribe(() => logger.push('status change'));
|
||||
|
||||
a.removeAt(1, {emitEvent: false});
|
||||
|
||||
expect(a.controls).toEqual([c1, c3]);
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
|
||||
it('should not emit events when calling `FormArray.clear` with `emitEvent: false`', () => {
|
||||
a.push(c1);
|
||||
a.push(c2);
|
||||
a.push(c3);
|
||||
|
||||
a.valueChanges.subscribe(() => logger.push('value change'));
|
||||
a.statusChanges.subscribe(() => logger.push('status change'));
|
||||
|
||||
a.clear({emitEvent: false});
|
||||
|
||||
expect(a.controls).toEqual([]);
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
|
||||
it('should not emit events when calling `FormArray.insert` with `emitEvent: false`', () => {
|
||||
a.push(c1);
|
||||
a.push(c3);
|
||||
|
||||
a.valueChanges.subscribe(() => logger.push('value change'));
|
||||
a.statusChanges.subscribe(() => logger.push('status change'));
|
||||
|
||||
a.insert(1, c2, {emitEvent: false});
|
||||
|
||||
expect(a.controls).toEqual([c1, c2, c3]);
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
|
||||
it('should not emit events when calling `FormArray.setControl` with `emitEvent: false`', () => {
|
||||
a.push(c1);
|
||||
a.push(c3);
|
||||
|
||||
a.valueChanges.subscribe(() => logger.push('value change'));
|
||||
a.statusChanges.subscribe(() => logger.push('status change'));
|
||||
|
||||
a.setControl(1, c2, {emitEvent: false});
|
||||
|
||||
expect(a.controls).toEqual([c1, c2]);
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
|
||||
it('should not emit status change events when `FormArray.push` is called with `emitEvent: false`',
|
||||
() => {
|
||||
// Adding validators to make sure there are no status change event submitted when form
|
||||
// becomes invalid.
|
||||
const validatorFn = (value: any) => value.controls.length > 0 ? {controls: true} : null;
|
||||
const asyncValidatorFn = (value: any) => of(validatorFn(value));
|
||||
const arr = new FormArray([], validatorFn, asyncValidatorFn);
|
||||
expect(arr.valid).toBe(true);
|
||||
|
||||
arr.statusChanges.subscribe(() => logger.push('status change'));
|
||||
|
||||
arr.push(c1, {emitEvent: false});
|
||||
|
||||
expect(arr.valid).toBe(false);
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
|
||||
it('should not emit events on the parent when called with `emitEvent: false`', () => {
|
||||
const form = new FormGroup({child: a});
|
||||
|
||||
form.valueChanges.subscribe(() => logger.push('form value change'));
|
||||
a.valueChanges.subscribe(() => logger.push('array value change'));
|
||||
form.statusChanges.subscribe(() => logger.push('form status change'));
|
||||
a.statusChanges.subscribe(() => logger.push('array status change'));
|
||||
|
||||
a.push(new FormControl(5), {emitEvent: false});
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('value', () => {
|
||||
@ -235,23 +331,15 @@ describe('FormArray', () => {
|
||||
expect(logger).toEqual(['control1', 'control2', 'array', 'form']);
|
||||
});
|
||||
|
||||
it('should not fire an event when explicitly specified', fakeAsync(() => {
|
||||
form.valueChanges.subscribe((value) => {
|
||||
throw 'Should not happen';
|
||||
});
|
||||
a.valueChanges.subscribe((value) => {
|
||||
throw 'Should not happen';
|
||||
});
|
||||
c.valueChanges.subscribe((value) => {
|
||||
throw 'Should not happen';
|
||||
});
|
||||
c2.valueChanges.subscribe((value) => {
|
||||
throw 'Should not happen';
|
||||
});
|
||||
it('should not fire events when called with `emitEvent: false`', () => {
|
||||
form.valueChanges.subscribe(() => logger.push('form'));
|
||||
a.valueChanges.subscribe(() => logger.push('array'));
|
||||
c.valueChanges.subscribe(() => logger.push('control1'));
|
||||
c2.valueChanges.subscribe(() => logger.push('control2'));
|
||||
|
||||
a.setValue(['one', 'two'], {emitEvent: false});
|
||||
tick();
|
||||
}));
|
||||
a.setValue(['one', 'two'], {emitEvent: false});
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
|
||||
it('should emit one statusChange event per control', () => {
|
||||
form.statusChanges.subscribe(() => logger.push('form'));
|
||||
@ -386,23 +474,15 @@ describe('FormArray', () => {
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
|
||||
it('should not fire an event when explicitly specified', fakeAsync(() => {
|
||||
form.valueChanges.subscribe((value) => {
|
||||
throw 'Should not happen';
|
||||
});
|
||||
a.valueChanges.subscribe((value) => {
|
||||
throw 'Should not happen';
|
||||
});
|
||||
c.valueChanges.subscribe((value) => {
|
||||
throw 'Should not happen';
|
||||
});
|
||||
c2.valueChanges.subscribe((value) => {
|
||||
throw 'Should not happen';
|
||||
});
|
||||
it('should not fire events when called with `emitEvent: false`', () => {
|
||||
form.valueChanges.subscribe(() => logger.push('form'));
|
||||
a.valueChanges.subscribe(() => logger.push('array'));
|
||||
c.valueChanges.subscribe(() => logger.push('control1'));
|
||||
c2.valueChanges.subscribe(() => logger.push('control2'));
|
||||
|
||||
a.patchValue(['one', 'two'], {emitEvent: false});
|
||||
tick();
|
||||
}));
|
||||
a.patchValue(['one', 'two'], {emitEvent: false});
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
|
||||
it('should emit one statusChange event per control', () => {
|
||||
form.statusChanges.subscribe(() => logger.push('form'));
|
||||
@ -605,26 +685,16 @@ describe('FormArray', () => {
|
||||
expect(logger).toEqual(['control1', 'control2', 'array', 'form']);
|
||||
});
|
||||
|
||||
it('should not fire an event when explicitly specified', fakeAsync(() => {
|
||||
form.valueChanges.subscribe((value) => {
|
||||
throw 'Should not happen';
|
||||
});
|
||||
a.valueChanges.subscribe((value) => {
|
||||
throw 'Should not happen';
|
||||
});
|
||||
c.valueChanges.subscribe((value) => {
|
||||
throw 'Should not happen';
|
||||
});
|
||||
c2.valueChanges.subscribe((value) => {
|
||||
throw 'Should not happen';
|
||||
});
|
||||
c3.valueChanges.subscribe((value) => {
|
||||
throw 'Should not happen';
|
||||
});
|
||||
it('should not fire events when called with `emitEvent: false`', () => {
|
||||
form.valueChanges.subscribe(() => logger.push('form'));
|
||||
a.valueChanges.subscribe(() => logger.push('array'));
|
||||
c.valueChanges.subscribe(() => logger.push('control1'));
|
||||
c2.valueChanges.subscribe(() => logger.push('control2'));
|
||||
c3.valueChanges.subscribe(() => logger.push('control3'));
|
||||
|
||||
a.reset([], {emitEvent: false});
|
||||
tick();
|
||||
}));
|
||||
a.reset([], {emitEvent: false});
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
|
||||
it('should emit one statusChange event per reset control', () => {
|
||||
form.statusChanges.subscribe(() => logger.push('form'));
|
||||
@ -764,7 +834,7 @@ describe('FormArray', () => {
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
|
||||
it('should not emit event when emitEvent = false', () => {
|
||||
it('should not emit events when called with `emitEvent: false`', () => {
|
||||
c.markAsPending({emitEvent: false});
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
@ -1211,7 +1281,7 @@ describe('FormArray', () => {
|
||||
expect(logger).toEqual(['control', 'array', 'form']);
|
||||
});
|
||||
|
||||
it('should not emit value change events when emitEvent = false', () => {
|
||||
it('should not emit value change events when called with `emitEvent: false`', () => {
|
||||
c.valueChanges.subscribe(() => logger.push('control'));
|
||||
a.valueChanges.subscribe(() => logger.push('array'));
|
||||
form.valueChanges.subscribe(() => logger.push('form'));
|
||||
@ -1222,7 +1292,7 @@ describe('FormArray', () => {
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
|
||||
it('should not emit status change events when emitEvent = false', () => {
|
||||
it('should not emit status change events when called with `emitEvent: false`', () => {
|
||||
c.statusChanges.subscribe(() => logger.push('control'));
|
||||
a.statusChanges.subscribe(() => logger.push('array'));
|
||||
form.statusChanges.subscribe(() => logger.push('form'));
|
||||
|
@ -126,6 +126,12 @@ describe('FormGroup', () => {
|
||||
});
|
||||
|
||||
describe('adding and removing controls', () => {
|
||||
let logger: any[];
|
||||
|
||||
beforeEach(() => {
|
||||
logger = [];
|
||||
});
|
||||
|
||||
it('should update value and validity when control is added', () => {
|
||||
const g = new FormGroup({'one': new FormControl('1')});
|
||||
expect(g.value).toEqual({'one': '1'});
|
||||
@ -148,6 +154,54 @@ describe('FormGroup', () => {
|
||||
expect(g.value).toEqual({'one': '1'});
|
||||
expect(g.valid).toBe(true);
|
||||
});
|
||||
|
||||
it('should not emit events when `FormGroup.addControl` is called with `emitEvent: false`',
|
||||
() => {
|
||||
const g = new FormGroup({'one': new FormControl('1')});
|
||||
expect(g.value).toEqual({'one': '1'});
|
||||
|
||||
g.valueChanges.subscribe(() => logger.push('value change'));
|
||||
g.statusChanges.subscribe(() => logger.push('status change'));
|
||||
|
||||
g.addControl('two', new FormControl('2'), {emitEvent: false});
|
||||
|
||||
expect(g.value).toEqual({'one': '1', 'two': '2'});
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
|
||||
it('should not emit events when `FormGroup.removeControl` is called with `emitEvent: false`',
|
||||
() => {
|
||||
const g = new FormGroup(
|
||||
{'one': new FormControl('1'), 'two': new FormControl('2', Validators.minLength(10))});
|
||||
expect(g.value).toEqual({'one': '1', 'two': '2'});
|
||||
expect(g.valid).toBe(false);
|
||||
|
||||
g.valueChanges.subscribe(() => logger.push('value change'));
|
||||
g.statusChanges.subscribe(() => logger.push('status change'));
|
||||
|
||||
g.removeControl('two', {emitEvent: false});
|
||||
|
||||
expect(g.value).toEqual({'one': '1'});
|
||||
expect(g.valid).toBe(true);
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
|
||||
it('should not emit status change events when `FormGroup.addControl` is called with `emitEvent: false`',
|
||||
() => {
|
||||
const validatorFn = (value: any) =>
|
||||
value.controls.invalidCtrl ? {invalidCtrl: true} : null;
|
||||
const asyncValidatorFn = (value: any) => of(validatorFn(value));
|
||||
const g = new FormGroup({}, validatorFn, asyncValidatorFn);
|
||||
expect(g.valid).toBe(true);
|
||||
|
||||
g.statusChanges.subscribe(() => logger.push('status change'));
|
||||
|
||||
g.addControl('invalidCtrl', new FormControl(''), {emitEvent: false});
|
||||
|
||||
expect(g.value).toEqual({'invalidCtrl': ''});
|
||||
expect(g.valid).toBe(false);
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('dirty', () => {
|
||||
@ -283,20 +337,15 @@ describe('FormGroup', () => {
|
||||
expect(logger).toEqual(['control1', 'control2', 'group', 'form']);
|
||||
});
|
||||
|
||||
it('should not fire an event when explicitly specified', fakeAsync(() => {
|
||||
form.valueChanges.subscribe((value) => {
|
||||
throw 'Should not happen';
|
||||
});
|
||||
g.valueChanges.subscribe((value) => {
|
||||
throw 'Should not happen';
|
||||
});
|
||||
c.valueChanges.subscribe((value) => {
|
||||
throw 'Should not happen';
|
||||
});
|
||||
it('should not emit events when `FormGroup.setValue` is called with `emitEvent: false`',
|
||||
() => {
|
||||
form.valueChanges.subscribe(() => logger.push('form'));
|
||||
g.valueChanges.subscribe(() => logger.push('group'));
|
||||
c.valueChanges.subscribe(() => logger.push('control'));
|
||||
|
||||
g.setValue({'one': 'one', 'two': 'two'}, {emitEvent: false});
|
||||
tick();
|
||||
}));
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
|
||||
it('should emit one statusChange event per control', () => {
|
||||
form.statusChanges.subscribe(() => logger.push('form'));
|
||||
@ -307,6 +356,16 @@ describe('FormGroup', () => {
|
||||
g.setValue({'one': 'one', 'two': 'two'});
|
||||
expect(logger).toEqual(['control1', 'control2', 'group', 'form']);
|
||||
});
|
||||
|
||||
it('should not emit events on the parent when called with `emitEvent: false`', () => {
|
||||
form.valueChanges.subscribe(() => logger.push('form value change'));
|
||||
g.valueChanges.subscribe(() => logger.push('group value change'));
|
||||
form.statusChanges.subscribe(() => logger.push('form status change'));
|
||||
g.statusChanges.subscribe(() => logger.push('group status change'));
|
||||
|
||||
g.addControl('three', new FormControl(5), {emitEvent: false});
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -444,20 +503,15 @@ describe('FormGroup', () => {
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
|
||||
it('should not fire an event when explicitly specified', fakeAsync(() => {
|
||||
form.valueChanges.subscribe((value) => {
|
||||
throw 'Should not happen';
|
||||
});
|
||||
g.valueChanges.subscribe((value) => {
|
||||
throw 'Should not happen';
|
||||
});
|
||||
c.valueChanges.subscribe((value) => {
|
||||
throw 'Should not happen';
|
||||
});
|
||||
it('should not emit events when `FormGroup.patchValue` is called with `emitEvent: false`',
|
||||
() => {
|
||||
form.valueChanges.subscribe(() => logger.push('form'));
|
||||
g.valueChanges.subscribe(() => logger.push('group'));
|
||||
c.valueChanges.subscribe(() => logger.push('control'));
|
||||
|
||||
g.patchValue({'one': 'one', 'two': 'two'}, {emitEvent: false});
|
||||
tick();
|
||||
}));
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
|
||||
it('should emit one statusChange event per control', () => {
|
||||
form.statusChanges.subscribe(() => logger.push('form'));
|
||||
@ -659,20 +713,14 @@ describe('FormGroup', () => {
|
||||
expect(logger).toEqual(['control1', 'control2', 'group', 'form']);
|
||||
});
|
||||
|
||||
it('should not fire an event when explicitly specified', fakeAsync(() => {
|
||||
form.valueChanges.subscribe((value) => {
|
||||
throw 'Should not happen';
|
||||
});
|
||||
g.valueChanges.subscribe((value) => {
|
||||
throw 'Should not happen';
|
||||
});
|
||||
c.valueChanges.subscribe((value) => {
|
||||
throw 'Should not happen';
|
||||
});
|
||||
it('should not emit events when `FormGroup.reset` is called with `emitEvent: false`', () => {
|
||||
form.valueChanges.subscribe(() => logger.push('form'));
|
||||
g.valueChanges.subscribe(() => logger.push('group'));
|
||||
c.valueChanges.subscribe(() => logger.push('control'));
|
||||
|
||||
g.reset({}, {emitEvent: false});
|
||||
tick();
|
||||
}));
|
||||
g.reset({}, {emitEvent: false});
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
|
||||
it('should emit one statusChange event per reset control', () => {
|
||||
form.statusChanges.subscribe(() => logger.push('form'));
|
||||
@ -1769,7 +1817,7 @@ describe('FormGroup', () => {
|
||||
expect(logger).toEqual(['control', 'group', 'form']);
|
||||
});
|
||||
|
||||
it('should not emit value change events when emitEvent = false', () => {
|
||||
it('should not emit value change events when called with `emitEvent: false`', () => {
|
||||
c.valueChanges.subscribe(() => logger.push('control'));
|
||||
g.valueChanges.subscribe(() => logger.push('group'));
|
||||
form.valueChanges.subscribe(() => logger.push('form'));
|
||||
@ -1780,7 +1828,7 @@ describe('FormGroup', () => {
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
|
||||
it('should not emit status change events when emitEvent = false', () => {
|
||||
it('should not emit status change events when called with `emitEvent: false`', () => {
|
||||
c.statusChanges.subscribe(() => logger.push('control'));
|
||||
g.statusChanges.subscribe(() => logger.push('group'));
|
||||
form.statusChanges.subscribe(() => logger.push('form'));
|
||||
@ -1818,7 +1866,7 @@ describe('FormGroup', () => {
|
||||
expect(logger).toEqual(['one', 'two', 'nested', 'three', 'form']);
|
||||
});
|
||||
|
||||
it('should not emit events when turned off', () => {
|
||||
it('should not emit events when called with `emitEvent: false`', () => {
|
||||
(form as any)._updateTreeValidity({emitEvent: false});
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
@ -1864,6 +1912,15 @@ describe('FormGroup', () => {
|
||||
g.setControl('one', c2);
|
||||
expect(logger).toEqual(['change!']);
|
||||
});
|
||||
|
||||
it('should not emit event called when `FormGroup.setControl` with `emitEvent: false`', () => {
|
||||
const logger: string[] = [];
|
||||
const c2 = new FormControl('new!');
|
||||
g.valueChanges.subscribe(() => logger.push('value change'));
|
||||
g.statusChanges.subscribe(() => logger.push('status change'));
|
||||
g.setControl('one', c2, {emitEvent: false});
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('emit `statusChanges` and `valueChanges` with/without async/sync validators', () => {
|
||||
@ -2292,7 +2349,7 @@ describe('FormGroup', () => {
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
|
||||
it('should not emit event when emitEvent = false', () => {
|
||||
it('should not emit event when called with `emitEvent: false`', () => {
|
||||
c.markAsPending({emitEvent: false});
|
||||
expect(logger).toEqual([]);
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user