From c598636847aa944b386d484fdd4f0e162e308e22 Mon Sep 17 00:00:00 2001 From: Florian Kinder Date: Tue, 11 Oct 2016 22:03:16 +0200 Subject: [PATCH 1/2] feat(forms): Added emitEvent to AbstractControl methods --- modules/@angular/forms/src/model.ts | 57 +++++++++++-------- .../@angular/forms/test/form_array_spec.ts | 31 ++++++++++ .../@angular/forms/test/form_control_spec.ts | 10 ++++ .../@angular/forms/test/form_group_spec.ts | 27 +++++++++ tools/public_api_guard/forms/index.d.ts | 21 ++++--- 5 files changed, 115 insertions(+), 31 deletions(-) diff --git a/modules/@angular/forms/src/model.ts b/modules/@angular/forms/src/model.ts index 48975d323a68..c38a21a0bc9e 100644 --- a/modules/@angular/forms/src/model.ts +++ b/modules/@angular/forms/src/model.ts @@ -741,11 +741,12 @@ export class FormControl extends AbstractControl { * console.log(this.control.status); // 'DISABLED' * ``` */ - reset(formState: any = null, {onlySelf}: {onlySelf?: boolean} = {}): void { + reset(formState: any = null, {onlySelf, emitEvent}: {onlySelf?: boolean, + emitEvent?: boolean} = {}): void { this._applyFormState(formState); this.markAsPristine({onlySelf}); this.markAsUntouched({onlySelf}); - this.setValue(this._value, {onlySelf}); + this.setValue(this._value, {onlySelf, emitEvent}); } /** @@ -938,13 +939,15 @@ export class FormGroup extends AbstractControl { * * ``` */ - setValue(value: {[key: string]: any}, {onlySelf}: {onlySelf?: boolean} = {}): void { + setValue( + value: {[key: string]: any}, + {onlySelf, emitEvent}: {onlySelf?: boolean, emitEvent?: boolean} = {}): void { this._checkAllValuesPresent(value); Object.keys(value).forEach(name => { this._throwIfControlMissing(name); - this.controls[name].setValue(value[name], {onlySelf: true}); + this.controls[name].setValue(value[name], {onlySelf: true, emitEvent}); }); - this.updateValueAndValidity({onlySelf: onlySelf}); + this.updateValueAndValidity({onlySelf: onlySelf, emitEvent}); } /** @@ -968,13 +971,15 @@ export class FormGroup extends AbstractControl { * * ``` */ - patchValue(value: {[key: string]: any}, {onlySelf}: {onlySelf?: boolean} = {}): void { + patchValue( + value: {[key: string]: any}, + {onlySelf, emitEvent}: {onlySelf?: boolean, emitEvent?: boolean} = {}): void { Object.keys(value).forEach(name => { if (this.controls[name]) { - this.controls[name].patchValue(value[name], {onlySelf: true}); + this.controls[name].patchValue(value[name], {onlySelf: true, emitEvent}); } }); - this.updateValueAndValidity({onlySelf: onlySelf}); + this.updateValueAndValidity({onlySelf: onlySelf, emitEvent}); } /** @@ -1009,13 +1014,14 @@ export class FormGroup extends AbstractControl { * console.log(this.form.get('first').status); // 'DISABLED' * ``` */ - reset(value: any = {}, {onlySelf}: {onlySelf?: boolean} = {}): void { + reset(value: any = {}, {onlySelf, emitEvent}: {onlySelf?: boolean, emitEvent?: boolean} = {}): + void { this._forEachChild((control: AbstractControl, name: string) => { - control.reset(value[name], {onlySelf: true}); + control.reset(value[name], {onlySelf: true, emitEvent}); }); - this.updateValueAndValidity({onlySelf: onlySelf}); - this._updatePristine({onlySelf: onlySelf}); - this._updateTouched({onlySelf: onlySelf}); + this.updateValueAndValidity({onlySelf, emitEvent}); + this._updatePristine({onlySelf}); + this._updateTouched({onlySelf}); } /** @@ -1240,13 +1246,14 @@ export class FormArray extends AbstractControl { * console.log(arr.value); // ['Nancy', 'Drew'] * ``` */ - setValue(value: any[], {onlySelf}: {onlySelf?: boolean} = {}): void { + setValue(value: any[], {onlySelf, emitEvent}: {onlySelf?: boolean, emitEvent?: boolean} = {}): + void { this._checkAllValuesPresent(value); value.forEach((newValue: any, index: number) => { this._throwIfControlMissing(index); - this.at(index).setValue(newValue, {onlySelf: true}); + this.at(index).setValue(newValue, {onlySelf: true, emitEvent}); }); - this.updateValueAndValidity({onlySelf: onlySelf}); + this.updateValueAndValidity({onlySelf: onlySelf, emitEvent}); } /** @@ -1269,13 +1276,14 @@ export class FormArray extends AbstractControl { * console.log(arr.value); // ['Nancy', null] * ``` */ - patchValue(value: any[], {onlySelf}: {onlySelf?: boolean} = {}): void { + patchValue(value: any[], {onlySelf, emitEvent}: {onlySelf?: boolean, emitEvent?: boolean} = {}): + void { value.forEach((newValue: any, index: number) => { if (this.at(index)) { - this.at(index).patchValue(newValue, {onlySelf: true}); + this.at(index).patchValue(newValue, {onlySelf: true, emitEvent}); } }); - this.updateValueAndValidity({onlySelf: onlySelf}); + this.updateValueAndValidity({onlySelf: onlySelf, emitEvent}); } /** @@ -1309,13 +1317,14 @@ export class FormArray extends AbstractControl { * console.log(this.arr.get(0).status); // 'DISABLED' * ``` */ - reset(value: any = [], {onlySelf}: {onlySelf?: boolean} = {}): void { + reset(value: any = [], {onlySelf, emitEvent}: {onlySelf?: boolean, emitEvent?: boolean} = {}): + void { this._forEachChild((control: AbstractControl, index: number) => { - control.reset(value[index], {onlySelf: true}); + control.reset(value[index], {onlySelf: true, emitEvent}); }); - this.updateValueAndValidity({onlySelf: onlySelf}); - this._updatePristine({onlySelf: onlySelf}); - this._updateTouched({onlySelf: onlySelf}); + this.updateValueAndValidity({onlySelf, emitEvent}); + this._updatePristine({onlySelf}); + this._updateTouched({onlySelf}); } /** diff --git a/modules/@angular/forms/test/form_array_spec.ts b/modules/@angular/forms/test/form_array_spec.ts index 76ba0644db8a..0f25ac3122f4 100644 --- a/modules/@angular/forms/test/form_array_spec.ts +++ b/modules/@angular/forms/test/form_array_spec.ts @@ -165,6 +165,16 @@ export function main() { 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'; }); + + a.setValue(['one', 'two'], {emitEvent: false}); + tick(); + })); + it('should emit one statusChange event per control', () => { form.statusChanges.subscribe(() => logger.push('form')); a.statusChanges.subscribe(() => logger.push('array')); @@ -263,6 +273,16 @@ export function main() { expect(logger).toEqual(['control1', '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'; }); + + a.patchValue(['one', 'two'], {emitEvent: false}); + tick(); + })); + it('should emit one statusChange event per control', () => { form.statusChanges.subscribe(() => logger.push('form')); a.statusChanges.subscribe(() => logger.push('array')); @@ -457,6 +477,17 @@ export function main() { 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'; }); + + a.reset([], {emitEvent: false}); + tick(); + })); + it('should emit one statusChange event per reset control', () => { form.statusChanges.subscribe(() => logger.push('form')); a.statusChanges.subscribe(() => logger.push('array')); diff --git a/modules/@angular/forms/test/form_control_spec.ts b/modules/@angular/forms/test/form_control_spec.ts index 4087d914e5c4..964d35fe1071 100644 --- a/modules/@angular/forms/test/form_control_spec.ts +++ b/modules/@angular/forms/test/form_control_spec.ts @@ -549,6 +549,16 @@ export function main() { expect(logger).toEqual(['control1', 'group']); }); + it('should not fire an event when explicitly specified', fakeAsync(() => { + g.valueChanges.subscribe((value) => { throw 'Should not happen'; }); + c.valueChanges.subscribe((value) => { throw 'Should not happen'; }); + c2.valueChanges.subscribe((value) => { throw 'Should not happen'; }); + + c.reset(null, {emitEvent: false}); + + tick(); + })); + it('should emit one statusChange event per reset control', () => { g.statusChanges.subscribe(() => logger.push('group')); c.statusChanges.subscribe(() => logger.push('control1')); diff --git a/modules/@angular/forms/test/form_group_spec.ts b/modules/@angular/forms/test/form_group_spec.ts index 0c1d131d26ad..de5f1a11bc1f 100644 --- a/modules/@angular/forms/test/form_group_spec.ts +++ b/modules/@angular/forms/test/form_group_spec.ts @@ -229,6 +229,15 @@ export function main() { 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'; }); + + g.setValue({'one': 'one', 'two': 'two'}, {emitEvent: false}); + tick(); + })); + it('should emit one statusChange event per control', () => { form.statusChanges.subscribe(() => logger.push('form')); g.statusChanges.subscribe(() => logger.push('group')); @@ -327,6 +336,15 @@ export function main() { expect(logger).toEqual(['control1', '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'; }); + + g.patchValue({'one': 'one', 'two': 'two'}, {emitEvent: false}); + tick(); + })); + it('should emit one statusChange event per control', () => { form.statusChanges.subscribe(() => logger.push('form')); g.statusChanges.subscribe(() => logger.push('group')); @@ -520,6 +538,15 @@ export function main() { 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'; }); + + g.reset({}, {emitEvent: false}); + tick(); + })); + it('should emit one statusChange event per reset control', () => { form.statusChanges.subscribe(() => logger.push('form')); g.statusChanges.subscribe(() => logger.push('group')); diff --git a/tools/public_api_guard/forms/index.d.ts b/tools/public_api_guard/forms/index.d.ts index 95bd3d06a0ac..c0166d5046ba 100644 --- a/tools/public_api_guard/forms/index.d.ts +++ b/tools/public_api_guard/forms/index.d.ts @@ -159,17 +159,20 @@ export declare class FormArray extends AbstractControl { at(index: number): AbstractControl; getRawValue(): any[]; insert(index: number, control: AbstractControl): void; - patchValue(value: any[], {onlySelf}?: { + patchValue(value: any[], {onlySelf, emitEvent}?: { onlySelf?: boolean; + emitEvent?: boolean; }): void; push(control: AbstractControl): void; removeAt(index: number): void; - reset(value?: any, {onlySelf}?: { + reset(value?: any, {onlySelf, emitEvent}?: { onlySelf?: boolean; + emitEvent?: boolean; }): void; setControl(index: number, control: AbstractControl): void; - setValue(value: any[], {onlySelf}?: { + setValue(value: any[], {onlySelf, emitEvent}?: { onlySelf?: boolean; + emitEvent?: boolean; }): void; } @@ -208,8 +211,9 @@ export declare class FormControl extends AbstractControl { }): void; registerOnChange(fn: Function): void; registerOnDisabledChange(fn: (isDisabled: boolean) => void): void; - reset(formState?: any, {onlySelf}?: { + reset(formState?: any, {onlySelf, emitEvent}?: { onlySelf?: boolean; + emitEvent?: boolean; }): void; setValue(value: any, {onlySelf, emitEvent, emitModelToViewChange, emitViewToModelChange}?: { onlySelf?: boolean; @@ -265,19 +269,22 @@ export declare class FormGroup extends AbstractControl { getRawValue(): Object; patchValue(value: { [key: string]: any; - }, {onlySelf}?: { + }, {onlySelf, emitEvent}?: { onlySelf?: boolean; + emitEvent?: boolean; }): void; registerControl(name: string, control: AbstractControl): AbstractControl; removeControl(name: string): void; - reset(value?: any, {onlySelf}?: { + reset(value?: any, {onlySelf, emitEvent}?: { onlySelf?: boolean; + emitEvent?: boolean; }): void; setControl(name: string, control: AbstractControl): void; setValue(value: { [key: string]: any; - }, {onlySelf}?: { + }, {onlySelf, emitEvent}?: { onlySelf?: boolean; + emitEvent?: boolean; }): void; } From 240b6c8a3ff60a7e187827a19e2b6d3ed3527f83 Mon Sep 17 00:00:00 2001 From: Florian Kinder Date: Tue, 11 Oct 2016 22:04:21 +0200 Subject: [PATCH 2/2] style(forms): unified named parameter --- modules/@angular/forms/src/model.ts | 32 ++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/modules/@angular/forms/src/model.ts b/modules/@angular/forms/src/model.ts index c38a21a0bc9e..fccd697c48e0 100644 --- a/modules/@angular/forms/src/model.ts +++ b/modules/@angular/forms/src/model.ts @@ -249,7 +249,7 @@ export abstract class AbstractControl { this._touched = true; if (isPresent(this._parent) && !onlySelf) { - this._parent.markAsTouched({onlySelf: onlySelf}); + this._parent.markAsTouched({onlySelf}); } } @@ -267,7 +267,7 @@ export abstract class AbstractControl { (control: AbstractControl) => { control.markAsUntouched({onlySelf: true}); }); if (isPresent(this._parent) && !onlySelf) { - this._parent._updateTouched({onlySelf: onlySelf}); + this._parent._updateTouched({onlySelf}); } } @@ -282,7 +282,7 @@ export abstract class AbstractControl { this._pristine = false; if (isPresent(this._parent) && !onlySelf) { - this._parent.markAsDirty({onlySelf: onlySelf}); + this._parent.markAsDirty({onlySelf}); } } @@ -299,7 +299,7 @@ export abstract class AbstractControl { this._forEachChild((control: AbstractControl) => { control.markAsPristine({onlySelf: true}); }); if (isPresent(this._parent) && !onlySelf) { - this._parent._updatePristine({onlySelf: onlySelf}); + this._parent._updatePristine({onlySelf}); } } @@ -311,7 +311,7 @@ export abstract class AbstractControl { this._status = PENDING; if (isPresent(this._parent) && !onlySelf) { - this._parent.markAsPending({onlySelf: onlySelf}); + this._parent.markAsPending({onlySelf}); } } @@ -348,7 +348,7 @@ export abstract class AbstractControl { enable({onlySelf, emitEvent}: {onlySelf?: boolean, emitEvent?: boolean} = {}): void { this._status = VALID; this._forEachChild((control: AbstractControl) => { control.enable({onlySelf: true}); }); - this.updateValueAndValidity({onlySelf: true, emitEvent: emitEvent}); + this.updateValueAndValidity({onlySelf: true, emitEvent}); this._updateAncestors(onlySelf); this._onDisabledChange.forEach((changeFn) => changeFn(false)); @@ -407,7 +407,7 @@ export abstract class AbstractControl { } if (isPresent(this._parent) && !onlySelf) { - this._parent.updateValueAndValidity({onlySelf: onlySelf, emitEvent: emitEvent}); + this._parent.updateValueAndValidity({onlySelf, emitEvent}); } } @@ -428,8 +428,8 @@ export abstract class AbstractControl { this._status = PENDING; this._cancelExistingSubscription(); var obs = toObservable(this.asyncValidator(this)); - this._asyncValidationSubscription = obs.subscribe( - {next: (res: {[key: string]: any}) => this.setErrors(res, {emitEvent: emitEvent})}); + this._asyncValidationSubscription = + obs.subscribe({next: (res: {[key: string]: any}) => this.setErrors(res, {emitEvent})}); } } @@ -582,7 +582,7 @@ export abstract class AbstractControl { this._pristine = !this._anyControlsDirty(); if (isPresent(this._parent) && !onlySelf) { - this._parent._updatePristine({onlySelf: onlySelf}); + this._parent._updatePristine({onlySelf}); } } @@ -591,7 +591,7 @@ export abstract class AbstractControl { this._touched = this._anyControlsTouched(); if (isPresent(this._parent) && !onlySelf) { - this._parent._updateTouched({onlySelf: onlySelf}); + this._parent._updateTouched({onlySelf}); } } @@ -694,7 +694,7 @@ export class FormControl extends AbstractControl { if (this._onChange.length && emitModelToViewChange) { this._onChange.forEach((changeFn) => changeFn(this._value, emitViewToModelChange)); } - this.updateValueAndValidity({onlySelf: onlySelf, emitEvent: emitEvent}); + this.updateValueAndValidity({onlySelf, emitEvent}); } /** @@ -947,7 +947,7 @@ export class FormGroup extends AbstractControl { this._throwIfControlMissing(name); this.controls[name].setValue(value[name], {onlySelf: true, emitEvent}); }); - this.updateValueAndValidity({onlySelf: onlySelf, emitEvent}); + this.updateValueAndValidity({onlySelf, emitEvent}); } /** @@ -979,7 +979,7 @@ export class FormGroup extends AbstractControl { this.controls[name].patchValue(value[name], {onlySelf: true, emitEvent}); } }); - this.updateValueAndValidity({onlySelf: onlySelf, emitEvent}); + this.updateValueAndValidity({onlySelf, emitEvent}); } /** @@ -1253,7 +1253,7 @@ export class FormArray extends AbstractControl { this._throwIfControlMissing(index); this.at(index).setValue(newValue, {onlySelf: true, emitEvent}); }); - this.updateValueAndValidity({onlySelf: onlySelf, emitEvent}); + this.updateValueAndValidity({onlySelf, emitEvent}); } /** @@ -1283,7 +1283,7 @@ export class FormArray extends AbstractControl { this.at(index).patchValue(newValue, {onlySelf: true, emitEvent}); } }); - this.updateValueAndValidity({onlySelf: onlySelf, emitEvent}); + this.updateValueAndValidity({onlySelf, emitEvent}); } /**