Skip to content

Commit eef9512

Browse files
choellerkara
authored andcommitted
fix(forms): async validator-directives process Observables correctly (#8186)
Closes #/8022
1 parent 9f00a1b commit eef9512

File tree

4 files changed

+52
-3
lines changed

4 files changed

+52
-3
lines changed

modules/@angular/common/src/forms-deprecated/directives/normalize_validator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export function normalizeValidator(validator: ValidatorFn | Validator): Validato
2020

2121
export function normalizeAsyncValidator(validator: AsyncValidatorFn | Validator): AsyncValidatorFn {
2222
if ((<Validator>validator).validate !== undefined) {
23-
return (c: AbstractControl) => Promise.resolve((<Validator>validator).validate(c));
23+
return (c: AbstractControl) => (<Validator>validator).validate(c);
2424
} else {
2525
return <AsyncValidatorFn>validator;
2626
}

modules/@angular/common/test/forms-deprecated/validators_spec.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
import {AbstractControl, Control, ControlArray, ControlGroup, Validators} from '@angular/common/src/forms-deprecated';
1010
import {fakeAsync, flushMicrotasks, tick} from '@angular/core/testing';
1111
import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal';
12+
import {Observable} from 'rxjs/Observable';
1213

1314
import {EventEmitter, ObservableWrapper, TimerWrapper} from '../../src/facade/async';
1415
import {PromiseWrapper} from '../../src/facade/promise';
16+
import {normalizeAsyncValidator} from '../../src/forms-deprecated/directives/normalize_validator';
1517

1618
export function main() {
1719
function validator(key: string, error: any) {
@@ -22,6 +24,18 @@ export function main() {
2224
}
2325
}
2426

27+
class AsyncValidatorDirective {
28+
constructor(private expected: string, private error: any) {}
29+
30+
validate(c: any): {[key: string]: any;} {
31+
return Observable.create((obs: any) => {
32+
const error = this.expected !== c.value ? this.error : null;
33+
obs.next(error);
34+
obs.complete();
35+
});
36+
}
37+
}
38+
2539
describe('Validators', () => {
2640
describe('required', () => {
2741
it('should error on an empty string',
@@ -88,6 +102,17 @@ export function main() {
88102
});
89103
});
90104

105+
it('should normalize and evaluate async validator-directives correctly', fakeAsync(() => {
106+
const c = Validators.composeAsync(
107+
[normalizeAsyncValidator(new AsyncValidatorDirective('expected', {'one': true}))]);
108+
109+
let value: any = null;
110+
c(new Control()).then((v: any) => value = v);
111+
tick(1);
112+
113+
expect(value).toEqual({'one': true});
114+
}));
115+
91116
describe('compose', () => {
92117
it('should return null when given null',
93118
() => { expect(Validators.compose(null)).toBe(null); });

modules/@angular/forms/src/directives/normalize_validator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export function normalizeValidator(validator: ValidatorFn | Validator): Validato
2020

2121
export function normalizeAsyncValidator(validator: AsyncValidatorFn | Validator): AsyncValidatorFn {
2222
if ((<Validator>validator).validate !== undefined) {
23-
return (c: AbstractControl) => Promise.resolve((<Validator>validator).validate(c));
23+
return (c: AbstractControl) => (<Validator>validator).validate(c);
2424
} else {
2525
return <AsyncValidatorFn>validator;
2626
}

modules/@angular/forms/test/validators_spec.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
import {fakeAsync, flushMicrotasks, tick} from '@angular/core/testing';
1010
import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal';
1111
import {AbstractControl, FormControl, Validators} from '@angular/forms';
12+
import {Observable} from 'rxjs/Observable';
1213

14+
import {normalizeAsyncValidator} from '../src/directives/normalize_validator';
1315
import {EventEmitter, ObservableWrapper, TimerWrapper} from '../src/facade/async';
1416
import {PromiseWrapper} from '../src/facade/promise';
1517

@@ -22,6 +24,18 @@ export function main() {
2224
}
2325
}
2426

27+
class AsyncValidatorDirective {
28+
constructor(private expected: string, private error: any) {}
29+
30+
validate(c: any): {[key: string]: any;} {
31+
return Observable.create((obs: any) => {
32+
const error = this.expected !== c.value ? this.error : null;
33+
obs.next(error);
34+
obs.complete();
35+
});
36+
}
37+
}
38+
2539
describe('Validators', () => {
2640
describe('required', () => {
2741
it('should error on an empty string',
@@ -147,12 +161,22 @@ export function main() {
147161
expect(value).toEqual({'one': true, 'two': true});
148162
}));
149163

164+
it('should normalize and evaluate async validator-directives correctly', fakeAsync(() => {
165+
const c = Validators.composeAsync(
166+
[normalizeAsyncValidator(new AsyncValidatorDirective('expected', {'one': true}))]);
167+
168+
let value: any = null;
169+
c(new FormControl()).then((v: any) => value = v);
170+
tick(1);
171+
172+
expect(value).toEqual({'one': true});
173+
}));
174+
150175
it('should return null when no errors', fakeAsync(() => {
151176
var c = Validators.composeAsync([asyncValidator('expected', {'one': true})]);
152177

153178
var value: any /** TODO #9100 */ = null;
154179
(<Promise<any>>c(new FormControl('expected'))).then(v => value = v);
155-
156180
tick(1);
157181

158182
expect(value).toEqual(null);

0 commit comments

Comments
 (0)