From 797914e94816e9eabf079d371c468a7de1f4c3dc Mon Sep 17 00:00:00 2001 From: Kara Date: Mon, 27 Jun 2016 21:01:24 -0600 Subject: [PATCH] fix(forms): emit statusChange when child controls have async validator (#9652) --- modules/@angular/forms/src/model.ts | 18 +++++++--------- modules/@angular/forms/test/model_spec.ts | 25 ++++++++++++++++++++--- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/modules/@angular/forms/src/model.ts b/modules/@angular/forms/src/model.ts index 4a93d3daa1..17ad84347e 100644 --- a/modules/@angular/forms/src/model.ts +++ b/modules/@angular/forms/src/model.ts @@ -213,15 +213,7 @@ export abstract class AbstractControl { emitEvent = isPresent(emitEvent) ? emitEvent : true; this._errors = errors; - this._status = this._calculateStatus(); - - if (emitEvent) { - ObservableWrapper.callEmit(this._statusChanges, this._status); - } - - if (isPresent(this._parent)) { - this._parent._updateControlsErrors(); - } + this._updateControlsErrors(emitEvent); } find(path: Array|string): AbstractControl { return _find(this, path); } @@ -250,11 +242,15 @@ export abstract class AbstractControl { } /** @internal */ - _updateControlsErrors(): void { + _updateControlsErrors(emitEvent: boolean): void { this._status = this._calculateStatus(); + if (emitEvent) { + ObservableWrapper.callEmit(this._statusChanges, this._status); + } + if (isPresent(this._parent)) { - this._parent._updateControlsErrors(); + this._parent._updateControlsErrors(emitEvent); } } diff --git a/modules/@angular/forms/test/model_spec.ts b/modules/@angular/forms/test/model_spec.ts index d16d1ab8a7..d6561188a6 100644 --- a/modules/@angular/forms/test/model_spec.ts +++ b/modules/@angular/forms/test/model_spec.ts @@ -7,7 +7,7 @@ */ import {fakeAsync, flushMicrotasks, tick} from '@angular/core/testing'; -import {afterEach, beforeEach, ddescribe, describe, expect, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; +import {afterEach, beforeEach, ddescribe, describe, iit, inject, it, xit} from '@angular/core/testing/testing_internal'; import {AsyncTestCompleter} from '@angular/core/testing/testing_internal'; import {FormArray, FormControl, FormGroup, Validators} from '@angular/forms'; @@ -34,7 +34,7 @@ export function main() { }; } - function asyncValidatorReturningObservable(c: any /** TODO #9100 */) { + function asyncValidatorReturningObservable(c: FormControl) { var e = new EventEmitter(); PromiseWrapper.scheduleMicrotask(() => ObservableWrapper.callEmit(e, {'async': true})); return e; @@ -581,7 +581,7 @@ export function main() { }); describe('valueChanges', () => { - var g: any /** TODO #9100 */, c1: any /** TODO #9100 */, c2: any /** TODO #9100 */; + var g: FormGroup, c1: FormControl, c2: FormControl; beforeEach(() => { c1 = new FormControl('old1'); @@ -662,6 +662,25 @@ export function main() { })); }); + describe('statusChanges', () => { + const control = new FormControl('', asyncValidatorReturningObservable); + const group = new FormGroup({'one': control}); + + // TODO(kara): update these tests to use fake Async + it('should fire a statusChange if child has async validation change', + inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + const loggedValues: string[] = []; + ObservableWrapper.subscribe(group.statusChanges, (status: string) => { + loggedValues.push(status); + if (loggedValues.length === 2) { + expect(loggedValues).toEqual(['PENDING', 'INVALID']); + } + async.done(); + }); + control.updateValue(''); + })); + }); + describe('getError', () => { it('should return the error when it is present', () => { var c = new FormControl('', Validators.required);