fix(forms): async validator-directives process Observables correctly (#8186)

Closes #/8022
This commit is contained in:
choeller 2016-06-27 00:52:50 +02:00 committed by Kara
parent 9f00a1b902
commit eef9512ce6
4 changed files with 52 additions and 3 deletions

View File

@ -20,7 +20,7 @@ export function normalizeValidator(validator: ValidatorFn | Validator): Validato
export function normalizeAsyncValidator(validator: AsyncValidatorFn | Validator): AsyncValidatorFn { export function normalizeAsyncValidator(validator: AsyncValidatorFn | Validator): AsyncValidatorFn {
if ((<Validator>validator).validate !== undefined) { if ((<Validator>validator).validate !== undefined) {
return (c: AbstractControl) => Promise.resolve((<Validator>validator).validate(c)); return (c: AbstractControl) => (<Validator>validator).validate(c);
} else { } else {
return <AsyncValidatorFn>validator; return <AsyncValidatorFn>validator;
} }

View File

@ -9,9 +9,11 @@
import {AbstractControl, Control, ControlArray, ControlGroup, Validators} from '@angular/common/src/forms-deprecated'; import {AbstractControl, Control, ControlArray, ControlGroup, Validators} from '@angular/common/src/forms-deprecated';
import {fakeAsync, flushMicrotasks, tick} from '@angular/core/testing'; import {fakeAsync, flushMicrotasks, tick} from '@angular/core/testing';
import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal'; import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal';
import {Observable} from 'rxjs/Observable';
import {EventEmitter, ObservableWrapper, TimerWrapper} from '../../src/facade/async'; import {EventEmitter, ObservableWrapper, TimerWrapper} from '../../src/facade/async';
import {PromiseWrapper} from '../../src/facade/promise'; import {PromiseWrapper} from '../../src/facade/promise';
import {normalizeAsyncValidator} from '../../src/forms-deprecated/directives/normalize_validator';
export function main() { export function main() {
function validator(key: string, error: any) { function validator(key: string, error: any) {
@ -22,6 +24,18 @@ export function main() {
} }
} }
class AsyncValidatorDirective {
constructor(private expected: string, private error: any) {}
validate(c: any): {[key: string]: any;} {
return Observable.create((obs: any) => {
const error = this.expected !== c.value ? this.error : null;
obs.next(error);
obs.complete();
});
}
}
describe('Validators', () => { describe('Validators', () => {
describe('required', () => { describe('required', () => {
it('should error on an empty string', it('should error on an empty string',
@ -88,6 +102,17 @@ export function main() {
}); });
}); });
it('should normalize and evaluate async validator-directives correctly', fakeAsync(() => {
const c = Validators.composeAsync(
[normalizeAsyncValidator(new AsyncValidatorDirective('expected', {'one': true}))]);
let value: any = null;
c(new Control()).then((v: any) => value = v);
tick(1);
expect(value).toEqual({'one': true});
}));
describe('compose', () => { describe('compose', () => {
it('should return null when given null', it('should return null when given null',
() => { expect(Validators.compose(null)).toBe(null); }); () => { expect(Validators.compose(null)).toBe(null); });

View File

@ -20,7 +20,7 @@ export function normalizeValidator(validator: ValidatorFn | Validator): Validato
export function normalizeAsyncValidator(validator: AsyncValidatorFn | Validator): AsyncValidatorFn { export function normalizeAsyncValidator(validator: AsyncValidatorFn | Validator): AsyncValidatorFn {
if ((<Validator>validator).validate !== undefined) { if ((<Validator>validator).validate !== undefined) {
return (c: AbstractControl) => Promise.resolve((<Validator>validator).validate(c)); return (c: AbstractControl) => (<Validator>validator).validate(c);
} else { } else {
return <AsyncValidatorFn>validator; return <AsyncValidatorFn>validator;
} }

View File

@ -9,7 +9,9 @@
import {fakeAsync, flushMicrotasks, tick} from '@angular/core/testing'; import {fakeAsync, flushMicrotasks, tick} from '@angular/core/testing';
import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal'; import {afterEach, beforeEach, ddescribe, describe, expect, iit, it, xit} from '@angular/core/testing/testing_internal';
import {AbstractControl, FormControl, Validators} from '@angular/forms'; import {AbstractControl, FormControl, Validators} from '@angular/forms';
import {Observable} from 'rxjs/Observable';
import {normalizeAsyncValidator} from '../src/directives/normalize_validator';
import {EventEmitter, ObservableWrapper, TimerWrapper} from '../src/facade/async'; import {EventEmitter, ObservableWrapper, TimerWrapper} from '../src/facade/async';
import {PromiseWrapper} from '../src/facade/promise'; import {PromiseWrapper} from '../src/facade/promise';
@ -22,6 +24,18 @@ export function main() {
} }
} }
class AsyncValidatorDirective {
constructor(private expected: string, private error: any) {}
validate(c: any): {[key: string]: any;} {
return Observable.create((obs: any) => {
const error = this.expected !== c.value ? this.error : null;
obs.next(error);
obs.complete();
});
}
}
describe('Validators', () => { describe('Validators', () => {
describe('required', () => { describe('required', () => {
it('should error on an empty string', it('should error on an empty string',
@ -147,12 +161,22 @@ export function main() {
expect(value).toEqual({'one': true, 'two': true}); expect(value).toEqual({'one': true, 'two': true});
})); }));
it('should normalize and evaluate async validator-directives correctly', fakeAsync(() => {
const c = Validators.composeAsync(
[normalizeAsyncValidator(new AsyncValidatorDirective('expected', {'one': true}))]);
let value: any = null;
c(new FormControl()).then((v: any) => value = v);
tick(1);
expect(value).toEqual({'one': true});
}));
it('should return null when no errors', fakeAsync(() => { it('should return null when no errors', fakeAsync(() => {
var c = Validators.composeAsync([asyncValidator('expected', {'one': true})]); var c = Validators.composeAsync([asyncValidator('expected', {'one': true})]);
var value: any /** TODO #9100 */ = null; var value: any /** TODO #9100 */ = null;
(<Promise<any>>c(new FormControl('expected'))).then(v => value = v); (<Promise<any>>c(new FormControl('expected'))).then(v => value = v);
tick(1); tick(1);
expect(value).toEqual(null); expect(value).toEqual(null);