feat(forms): add support for adding async validators via template
Example:
@Directive({
  selector: '[uniq-login-validator]',
  providers: [provide(NG_ASYNC_VALIDATORS, {useExisting: UniqLoginValidator, multi: true})]
})
class UniqLoginValidator implements Validator {
  validate(c) { return someFunctionReturningPromiseOrObservable(); }
}
			
			
This commit is contained in:
		
							parent
							
								
									cf449ddaa9
								
							
						
					
					
						commit
						31c12af81f
					
				| @ -33,7 +33,7 @@ export { | |||||||
|   SelectControlValueAccessor |   SelectControlValueAccessor | ||||||
| } from './forms/directives/select_control_value_accessor'; | } from './forms/directives/select_control_value_accessor'; | ||||||
| export {FORM_DIRECTIVES} from './forms/directives'; | export {FORM_DIRECTIVES} from './forms/directives'; | ||||||
| export {NG_VALIDATORS, Validators} from './forms/validators'; | export {NG_VALIDATORS, NG_ASYNC_VALIDATORS, Validators} from './forms/validators'; | ||||||
| export { | export { | ||||||
|   RequiredValidator, |   RequiredValidator, | ||||||
|   MinLengthValidator, |   MinLengthValidator, | ||||||
|  | |||||||
| @ -13,6 +13,7 @@ export abstract class NgControl extends AbstractControlDirective { | |||||||
|   valueAccessor: ControlValueAccessor = null; |   valueAccessor: ControlValueAccessor = null; | ||||||
| 
 | 
 | ||||||
|   get validator(): Function { return unimplemented(); } |   get validator(): Function { return unimplemented(); } | ||||||
|  |   get asyncValidator(): Function { return unimplemented(); } | ||||||
| 
 | 
 | ||||||
|   abstract viewToModelUpdate(newValue: any): void; |   abstract viewToModelUpdate(newValue: any): void; | ||||||
| } | } | ||||||
|  | |||||||
| @ -5,10 +5,10 @@ import {ListWrapper} from 'angular2/src/core/facade/collection'; | |||||||
| import {CONST_EXPR} from 'angular2/src/core/facade/lang'; | import {CONST_EXPR} from 'angular2/src/core/facade/lang'; | ||||||
| 
 | 
 | ||||||
| import {ControlContainer} from './control_container'; | import {ControlContainer} from './control_container'; | ||||||
| import {controlPath} from './shared'; | import {controlPath, composeValidators, composeAsyncValidators} from './shared'; | ||||||
| import {ControlGroup} from '../model'; | import {ControlGroup} from '../model'; | ||||||
| import {Form} from './form_interface'; | import {Form} from './form_interface'; | ||||||
| import {Validators, NG_VALIDATORS} from '../validators'; | import {Validators, NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators'; | ||||||
| 
 | 
 | ||||||
| const controlGroupProvider = | const controlGroupProvider = | ||||||
|     CONST_EXPR(new Provider(ControlContainer, {useExisting: forwardRef(() => NgControlGroup)})); |     CONST_EXPR(new Provider(ControlContainer, {useExisting: forwardRef(() => NgControlGroup)})); | ||||||
| @ -72,13 +72,11 @@ export class NgControlGroup extends ControlContainer implements OnInit, | |||||||
|   /** @internal */ |   /** @internal */ | ||||||
|   _parent: ControlContainer; |   _parent: ControlContainer; | ||||||
| 
 | 
 | ||||||
|   private _validators: Function[]; |  | ||||||
| 
 |  | ||||||
|   constructor(@Host() @SkipSelf() parent: ControlContainer, |   constructor(@Host() @SkipSelf() parent: ControlContainer, | ||||||
|               @Optional() @Inject(NG_VALIDATORS) validators: Function[]) { |               @Optional() @Inject(NG_VALIDATORS) private _validators: any[], | ||||||
|  |               @Optional() @Inject(NG_ASYNC_VALIDATORS) private _asyncValidators: any[]) { | ||||||
|     super(); |     super(); | ||||||
|     this._parent = parent; |     this._parent = parent; | ||||||
|     this._validators = validators; |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   onInit(): void { this.formDirective.addControlGroup(this); } |   onInit(): void { this.formDirective.addControlGroup(this); } | ||||||
| @ -100,5 +98,7 @@ export class NgControlGroup extends ControlContainer implements OnInit, | |||||||
|    */ |    */ | ||||||
|   get formDirective(): Form { return this._parent.formDirective; } |   get formDirective(): Form { return this._parent.formDirective; } | ||||||
| 
 | 
 | ||||||
|   get validator(): Function { return Validators.compose(this._validators); } |   get validator(): Function { return composeValidators(this._validators); } | ||||||
|  | 
 | ||||||
|  |   get asyncValidator(): Function { return composeAsyncValidators(this._asyncValidators); } | ||||||
| } | } | ||||||
|  | |||||||
| @ -8,9 +8,15 @@ import {forwardRef, Host, SkipSelf, Provider, Inject, Optional} from 'angular2/s | |||||||
| import {ControlContainer} from './control_container'; | import {ControlContainer} from './control_container'; | ||||||
| import {NgControl} from './ng_control'; | import {NgControl} from './ng_control'; | ||||||
| import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor'; | import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor'; | ||||||
| import {controlPath, composeValidators, isPropertyUpdated, selectValueAccessor} from './shared'; | import { | ||||||
|  |   controlPath, | ||||||
|  |   composeValidators, | ||||||
|  |   composeAsyncValidators, | ||||||
|  |   isPropertyUpdated, | ||||||
|  |   selectValueAccessor | ||||||
|  | } from './shared'; | ||||||
| import {Control} from '../model'; | import {Control} from '../model'; | ||||||
| import {Validators, NG_VALIDATORS} from '../validators'; | import {Validators, NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators'; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| const controlNameBinding = | const controlNameBinding = | ||||||
| @ -81,21 +87,18 @@ const controlNameBinding = | |||||||
| export class NgControlName extends NgControl implements OnChanges, | export class NgControlName extends NgControl implements OnChanges, | ||||||
|     OnDestroy { |     OnDestroy { | ||||||
|   /** @internal */ |   /** @internal */ | ||||||
|   _parent: ControlContainer; |  | ||||||
|   update = new EventEmitter(); |   update = new EventEmitter(); | ||||||
|   model: any; |   model: any; | ||||||
|   viewModel: any; |   viewModel: any; | ||||||
|   private _validator: Function; |   private _added = false; | ||||||
|   /** @internal */ |  | ||||||
|   _added = false; |  | ||||||
| 
 | 
 | ||||||
|   constructor(@Host() @SkipSelf() parent: ControlContainer, |   constructor(@Host() @SkipSelf() private _parent: ControlContainer, | ||||||
|               @Optional() @Inject(NG_VALIDATORS) validators: |               @Optional() @Inject(NG_VALIDATORS) private _validators: | ||||||
|  |                   /* Array<Validator|Function> */ any[], | ||||||
|  |               @Optional() @Inject(NG_ASYNC_VALIDATORS) private _asyncValidators: | ||||||
|                   /* Array<Validator|Function> */ any[], |                   /* Array<Validator|Function> */ any[], | ||||||
|               @Optional() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[]) { |               @Optional() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[]) { | ||||||
|     super(); |     super(); | ||||||
|     this._parent = parent; |  | ||||||
|     this._validator = composeValidators(validators); |  | ||||||
|     this.valueAccessor = selectValueAccessor(this, valueAccessors); |     this.valueAccessor = selectValueAccessor(this, valueAccessors); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -121,7 +124,9 @@ export class NgControlName extends NgControl implements OnChanges, | |||||||
| 
 | 
 | ||||||
|   get formDirective(): any { return this._parent.formDirective; } |   get formDirective(): any { return this._parent.formDirective; } | ||||||
| 
 | 
 | ||||||
|   get validator(): Function { return this._validator; } |   get validator(): Function { return composeValidators(this._validators); } | ||||||
|  | 
 | ||||||
|  |   get asyncValidator(): Function { return composeAsyncValidators(this._asyncValidators); } | ||||||
| 
 | 
 | ||||||
|   get control(): Control { return this.formDirective.getControl(this); } |   get control(): Control { return this.formDirective.getControl(this); } | ||||||
| } | } | ||||||
|  | |||||||
| @ -13,8 +13,8 @@ import {Form} from './form_interface'; | |||||||
| import {NgControlGroup} from './ng_control_group'; | import {NgControlGroup} from './ng_control_group'; | ||||||
| import {ControlContainer} from './control_container'; | import {ControlContainer} from './control_container'; | ||||||
| import {AbstractControl, ControlGroup, Control} from '../model'; | import {AbstractControl, ControlGroup, Control} from '../model'; | ||||||
| import {setUpControl, setUpControlGroup} from './shared'; | import {setUpControl, setUpControlGroup, composeValidators, composeAsyncValidators} from './shared'; | ||||||
| import {Validators, NG_VALIDATORS} from '../validators'; | import {Validators, NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators'; | ||||||
| 
 | 
 | ||||||
| const formDirectiveProvider = | const formDirectiveProvider = | ||||||
|     CONST_EXPR(new Provider(ControlContainer, {useExisting: forwardRef(() => NgForm)})); |     CONST_EXPR(new Provider(ControlContainer, {useExisting: forwardRef(() => NgForm)})); | ||||||
| @ -91,9 +91,11 @@ export class NgForm extends ControlContainer implements Form { | |||||||
|   form: ControlGroup; |   form: ControlGroup; | ||||||
|   ngSubmit = new EventEmitter(); |   ngSubmit = new EventEmitter(); | ||||||
| 
 | 
 | ||||||
|   constructor(@Optional() @Inject(NG_VALIDATORS) validators: Function[]) { |   constructor(@Optional() @Inject(NG_VALIDATORS) validators: any[], | ||||||
|  |               @Optional() @Inject(NG_ASYNC_VALIDATORS) asyncValidators: any[]) { | ||||||
|     super(); |     super(); | ||||||
|     this.form = new ControlGroup({}, null, Validators.compose(validators)); |     this.form = new ControlGroup({}, null, composeValidators(validators), | ||||||
|  |                                  composeAsyncValidators(asyncValidators)); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   get formDirective(): Form { return this; } |   get formDirective(): Form { return this; } | ||||||
|  | |||||||
| @ -7,9 +7,15 @@ import {Query, Directive} from 'angular2/src/core/metadata'; | |||||||
| import {forwardRef, Provider, Inject, Optional} from 'angular2/src/core/di'; | import {forwardRef, Provider, Inject, Optional} from 'angular2/src/core/di'; | ||||||
| import {NgControl} from './ng_control'; | import {NgControl} from './ng_control'; | ||||||
| import {Control} from '../model'; | import {Control} from '../model'; | ||||||
| import {Validators, NG_VALIDATORS} from '../validators'; | import {Validators, NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators'; | ||||||
| import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor'; | import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor'; | ||||||
| import {setUpControl, composeValidators, isPropertyUpdated, selectValueAccessor} from './shared'; | import { | ||||||
|  |   setUpControl, | ||||||
|  |   composeValidators, | ||||||
|  |   composeAsyncValidators, | ||||||
|  |   isPropertyUpdated, | ||||||
|  |   selectValueAccessor | ||||||
|  | } from './shared'; | ||||||
| 
 | 
 | ||||||
| const formControlBinding = | const formControlBinding = | ||||||
|     CONST_EXPR(new Provider(NgControl, {useExisting: forwardRef(() => NgFormControl)})); |     CONST_EXPR(new Provider(NgControl, {useExisting: forwardRef(() => NgFormControl)})); | ||||||
| @ -73,13 +79,13 @@ export class NgFormControl extends NgControl implements OnChanges { | |||||||
|   update = new EventEmitter(); |   update = new EventEmitter(); | ||||||
|   model: any; |   model: any; | ||||||
|   viewModel: any; |   viewModel: any; | ||||||
|   private _validator: Function; |  | ||||||
| 
 | 
 | ||||||
|   constructor(@Optional() @Inject(NG_VALIDATORS) validators: |   constructor(@Optional() @Inject(NG_VALIDATORS) private _validators: | ||||||
|  |                   /* Array<Validator|Function> */ any[], | ||||||
|  |               @Optional() @Inject(NG_ASYNC_VALIDATORS) private _asyncValidators: | ||||||
|                   /* Array<Validator|Function> */ any[], |                   /* Array<Validator|Function> */ any[], | ||||||
|               @Optional() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[]) { |               @Optional() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[]) { | ||||||
|     super(); |     super(); | ||||||
|     this._validator = composeValidators(validators); |  | ||||||
|     this.valueAccessor = selectValueAccessor(this, valueAccessors); |     this.valueAccessor = selectValueAccessor(this, valueAccessors); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -96,7 +102,9 @@ export class NgFormControl extends NgControl implements OnChanges { | |||||||
| 
 | 
 | ||||||
|   get path(): string[] { return []; } |   get path(): string[] { return []; } | ||||||
| 
 | 
 | ||||||
|   get validator(): Function { return this._validator; } |   get validator(): Function { return composeValidators(this._validators); } | ||||||
|  | 
 | ||||||
|  |   get asyncValidator(): Function { return composeAsyncValidators(this._asyncValidators); } | ||||||
| 
 | 
 | ||||||
|   get control(): Control { return this.form; } |   get control(): Control { return this.form; } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -11,8 +11,8 @@ import {NgControlGroup} from './ng_control_group'; | |||||||
| import {ControlContainer} from './control_container'; | import {ControlContainer} from './control_container'; | ||||||
| import {Form} from './form_interface'; | import {Form} from './form_interface'; | ||||||
| import {Control, ControlGroup} from '../model'; | import {Control, ControlGroup} from '../model'; | ||||||
| import {setUpControl, setUpControlGroup} from './shared'; | import {setUpControl, setUpControlGroup, composeValidators, composeAsyncValidators} from './shared'; | ||||||
| import {Validators, NG_VALIDATORS} from '../validators'; | import {Validators, NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators'; | ||||||
| 
 | 
 | ||||||
| const formDirectiveProvider = | const formDirectiveProvider = | ||||||
|     CONST_EXPR(new Provider(ControlContainer, {useExisting: forwardRef(() => NgFormModel)})); |     CONST_EXPR(new Provider(ControlContainer, {useExisting: forwardRef(() => NgFormModel)})); | ||||||
| @ -102,17 +102,21 @@ export class NgFormModel extends ControlContainer implements Form, | |||||||
|   form: ControlGroup = null; |   form: ControlGroup = null; | ||||||
|   directives: NgControl[] = []; |   directives: NgControl[] = []; | ||||||
|   ngSubmit = new EventEmitter(); |   ngSubmit = new EventEmitter(); | ||||||
|   private _validators: Function[]; |  | ||||||
| 
 | 
 | ||||||
|   constructor(@Optional() @Inject(NG_VALIDATORS) validators: Function[]) { |   constructor(@Optional() @Inject(NG_VALIDATORS) private _validators: any[], | ||||||
|  |               @Optional() @Inject(NG_ASYNC_VALIDATORS) private _asyncValidators: any[]) { | ||||||
|     super(); |     super(); | ||||||
|     this._validators = validators; |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   onChanges(changes: {[key: string]: SimpleChange}): void { |   onChanges(changes: {[key: string]: SimpleChange}): void { | ||||||
|     if (StringMapWrapper.contains(changes, "form")) { |     if (StringMapWrapper.contains(changes, "form")) { | ||||||
|       var c = Validators.compose(this._validators); |       var sync = composeValidators(this._validators); | ||||||
|       this.form.validator = Validators.compose([this.form.validator, c]); |       this.form.validator = Validators.compose([this.form.validator, sync]); | ||||||
|  | 
 | ||||||
|  |       var async = composeAsyncValidators(this._asyncValidators); | ||||||
|  |       this.form.asyncValidator = Validators.composeAsync([this.form.asyncValidator, async]); | ||||||
|  | 
 | ||||||
|  |       this.form.updateValueAndValidity({onlySelf: true, emitEvent: false}); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     this._updateDomValue(); |     this._updateDomValue(); | ||||||
|  | |||||||
| @ -7,8 +7,14 @@ import {forwardRef, Provider, Inject, Optional} from 'angular2/src/core/di'; | |||||||
| import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor'; | import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor'; | ||||||
| import {NgControl} from './ng_control'; | import {NgControl} from './ng_control'; | ||||||
| import {Control} from '../model'; | import {Control} from '../model'; | ||||||
| import {Validators, NG_VALIDATORS} from '../validators'; | import {Validators, NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators'; | ||||||
| import {setUpControl, isPropertyUpdated, selectValueAccessor, composeValidators} from './shared'; | import { | ||||||
|  |   setUpControl, | ||||||
|  |   isPropertyUpdated, | ||||||
|  |   selectValueAccessor, | ||||||
|  |   composeValidators, | ||||||
|  |   composeAsyncValidators | ||||||
|  | } from './shared'; | ||||||
| 
 | 
 | ||||||
| const formControlBinding = | const formControlBinding = | ||||||
|     CONST_EXPR(new Provider(NgControl, {useExisting: forwardRef(() => NgModel)})); |     CONST_EXPR(new Provider(NgControl, {useExisting: forwardRef(() => NgModel)})); | ||||||
| @ -49,13 +55,11 @@ export class NgModel extends NgControl implements OnChanges { | |||||||
|   update = new EventEmitter(); |   update = new EventEmitter(); | ||||||
|   model: any; |   model: any; | ||||||
|   viewModel: any; |   viewModel: any; | ||||||
|   private _validator: Function; |  | ||||||
| 
 | 
 | ||||||
|   constructor(@Optional() @Inject(NG_VALIDATORS) validators: |   constructor(@Optional() @Inject(NG_VALIDATORS) private _validators: any[], | ||||||
|                   /* Array<Validator|Function> */ any[], |               @Optional() @Inject(NG_ASYNC_VALIDATORS) private _asyncValidators: any[], | ||||||
|               @Optional() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[]) { |               @Optional() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[]) { | ||||||
|     super(); |     super(); | ||||||
|     this._validator = composeValidators(validators); |  | ||||||
|     this.valueAccessor = selectValueAccessor(this, valueAccessors); |     this.valueAccessor = selectValueAccessor(this, valueAccessors); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -76,7 +80,9 @@ export class NgModel extends NgControl implements OnChanges { | |||||||
| 
 | 
 | ||||||
|   get path(): string[] { return []; } |   get path(): string[] { return []; } | ||||||
| 
 | 
 | ||||||
|   get validator(): Function { return this._validator; } |   get validator(): Function { return composeValidators(this._validators); } | ||||||
|  | 
 | ||||||
|  |   get asyncValidator(): Function { return composeAsyncValidators(this._asyncValidators); } | ||||||
| 
 | 
 | ||||||
|   viewToModelUpdate(newValue: any): void { |   viewToModelUpdate(newValue: any): void { | ||||||
|     this.viewModel = newValue; |     this.viewModel = newValue; | ||||||
|  | |||||||
| @ -29,6 +29,7 @@ export function setUpControl(control: Control, dir: NgControl): void { | |||||||
|   if (isBlank(dir.valueAccessor)) _throwError(dir, "No value accessor for"); |   if (isBlank(dir.valueAccessor)) _throwError(dir, "No value accessor for"); | ||||||
| 
 | 
 | ||||||
|   control.validator = Validators.compose([control.validator, dir.validator]); |   control.validator = Validators.compose([control.validator, dir.validator]); | ||||||
|  |   control.asyncValidator = Validators.composeAsync([control.asyncValidator, dir.asyncValidator]); | ||||||
|   dir.valueAccessor.writeValue(control.value); |   dir.valueAccessor.writeValue(control.value); | ||||||
| 
 | 
 | ||||||
|   // view -> model
 |   // view -> model
 | ||||||
| @ -48,6 +49,7 @@ export function setUpControl(control: Control, dir: NgControl): void { | |||||||
| export function setUpControlGroup(control: ControlGroup, dir: NgControlGroup) { | export function setUpControlGroup(control: ControlGroup, dir: NgControlGroup) { | ||||||
|   if (isBlank(control)) _throwError(dir, "Cannot find control"); |   if (isBlank(control)) _throwError(dir, "Cannot find control"); | ||||||
|   control.validator = Validators.compose([control.validator, dir.validator]); |   control.validator = Validators.compose([control.validator, dir.validator]); | ||||||
|  |   control.asyncValidator = Validators.composeAsync([control.asyncValidator, dir.asyncValidator]); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function _throwError(dir: AbstractControlDirective, message: string): void { | function _throwError(dir: AbstractControlDirective, message: string): void { | ||||||
| @ -61,8 +63,12 @@ export function setProperty(renderer: Renderer, elementRef: ElementRef, propName | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function composeValidators(validators: /* Array<Validator|Function> */ any[]): Function { | export function composeValidators(validators: /* Array<Validator|Function> */ any[]): Function { | ||||||
|   return isPresent(validators) ? Validators.compose(validators.map(normalizeValidator)) : |   return isPresent(validators) ? Validators.compose(validators.map(normalizeValidator)) : null; | ||||||
|                                  Validators.nullValidator; | } | ||||||
|  | 
 | ||||||
|  | export function composeAsyncValidators( | ||||||
|  |     validators: /* Array<Validator|Function> */ any[]): Function { | ||||||
|  |   return isPresent(validators) ? Validators.composeAsync(validators.map(normalizeValidator)) : null; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function isPropertyUpdated(changes: {[key: string]: any}, viewModel: any): boolean { | export function isPropertyUpdated(changes: {[key: string]: any}, viewModel: any): boolean { | ||||||
|  | |||||||
| @ -142,8 +142,9 @@ export abstract class AbstractControl { | |||||||
|     if (isPresent(this.asyncValidator)) { |     if (isPresent(this.asyncValidator)) { | ||||||
|       this._status = PENDING; |       this._status = PENDING; | ||||||
|       this._cancelExistingSubscription(); |       this._cancelExistingSubscription(); | ||||||
|  |       var obs = ObservableWrapper.fromPromise(this.asyncValidator(this)); | ||||||
|       this._asyncValidationSubscription = |       this._asyncValidationSubscription = | ||||||
|           ObservableWrapper.subscribe(this.asyncValidator(this), res => this.setErrors(res)); |           ObservableWrapper.subscribe(obs, res => this.setErrors(res)); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -11,7 +11,8 @@ import { | |||||||
|   afterEach, |   afterEach, | ||||||
|   el, |   el, | ||||||
|   AsyncTestCompleter, |   AsyncTestCompleter, | ||||||
|   inject |   inject, | ||||||
|  |   tick | ||||||
| } from 'angular2/testing_internal'; | } from 'angular2/testing_internal'; | ||||||
| 
 | 
 | ||||||
| import {SpyNgControl, SpyValueAccessor} from '../spies'; | import {SpyNgControl, SpyValueAccessor} from '../spies'; | ||||||
| @ -38,7 +39,8 @@ import { | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| import {selectValueAccessor, composeValidators} from 'angular2/src/core/forms/directives/shared'; | import {selectValueAccessor, composeValidators} from 'angular2/src/core/forms/directives/shared'; | ||||||
| 
 | import {TimerWrapper} from 'angular2/src/core/facade/async'; | ||||||
|  | import {PromiseWrapper} from 'angular2/src/core/facade/promise'; | ||||||
| import {SimpleChange} from 'angular2/src/core/change_detection'; | import {SimpleChange} from 'angular2/src/core/change_detection'; | ||||||
| 
 | 
 | ||||||
| class DummyControlValueAccessor implements ControlValueAccessor { | class DummyControlValueAccessor implements ControlValueAccessor { | ||||||
| @ -54,6 +56,19 @@ class CustomValidatorDirective implements Validator { | |||||||
|   validate(c: Control): {[key: string]: any} { return {"custom": true}; } |   validate(c: Control): {[key: string]: any} { return {"custom": true}; } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | function asyncValidator(expected, timeout = 0) { | ||||||
|  |   return (c) => { | ||||||
|  |     var completer = PromiseWrapper.completer(); | ||||||
|  |     var res = c.value != expected ? {"async": true} : null; | ||||||
|  |     if (timeout == 0) { | ||||||
|  |       completer.resolve(res); | ||||||
|  |     } else { | ||||||
|  |       TimerWrapper.setTimeout(() => { completer.resolve(res); }, timeout); | ||||||
|  |     } | ||||||
|  |     return completer.promise; | ||||||
|  |   }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export function main() { | export function main() { | ||||||
|   describe("Form Directives", () => { |   describe("Form Directives", () => { | ||||||
|     var defaultAccessor; |     var defaultAccessor; | ||||||
| @ -125,7 +140,7 @@ export function main() { | |||||||
|       var loginControlDir; |       var loginControlDir; | ||||||
| 
 | 
 | ||||||
|       beforeEach(() => { |       beforeEach(() => { | ||||||
|         form = new NgFormModel([]); |         form = new NgFormModel([], []); | ||||||
|         formModel = new ControlGroup({ |         formModel = new ControlGroup({ | ||||||
|           "login": new Control(), |           "login": new Control(), | ||||||
|           "passwords": |           "passwords": | ||||||
| @ -133,7 +148,8 @@ export function main() { | |||||||
|         }); |         }); | ||||||
|         form.form = formModel; |         form.form = formModel; | ||||||
| 
 | 
 | ||||||
|         loginControlDir = new NgControlName(form, [Validators.required], [defaultAccessor]); |         loginControlDir = new NgControlName(form, [Validators.required], | ||||||
|  |                                             [asyncValidator("expected")], [defaultAccessor]); | ||||||
|         loginControlDir.name = "login"; |         loginControlDir.name = "login"; | ||||||
|         loginControlDir.valueAccessor = new DummyControlValueAccessor(); |         loginControlDir.valueAccessor = new DummyControlValueAccessor(); | ||||||
|       }); |       }); | ||||||
| @ -151,7 +167,7 @@ export function main() { | |||||||
| 
 | 
 | ||||||
|       describe("addControl", () => { |       describe("addControl", () => { | ||||||
|         it("should throw when no control found", () => { |         it("should throw when no control found", () => { | ||||||
|           var dir = new NgControlName(form, null, [defaultAccessor]); |           var dir = new NgControlName(form, null, null, [defaultAccessor]); | ||||||
|           dir.name = "invalidName"; |           dir.name = "invalidName"; | ||||||
| 
 | 
 | ||||||
|           expect(() => form.addControl(dir)) |           expect(() => form.addControl(dir)) | ||||||
| @ -159,21 +175,30 @@ export function main() { | |||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|         it("should throw when no value accessor", () => { |         it("should throw when no value accessor", () => { | ||||||
|           var dir = new NgControlName(form, null, null); |           var dir = new NgControlName(form, null, null, null); | ||||||
|           dir.name = "login"; |           dir.name = "login"; | ||||||
| 
 | 
 | ||||||
|           expect(() => form.addControl(dir)) |           expect(() => form.addControl(dir)) | ||||||
|               .toThrowError(new RegExp("No value accessor for 'login'")); |               .toThrowError(new RegExp("No value accessor for 'login'")); | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|         it("should set up validator", () => { |         it("should set up validators", fakeAsync(() => { | ||||||
|           expect(formModel.find(["login"]).valid).toBe(true); |  | ||||||
| 
 |  | ||||||
|           // this will add the required validator and recalculate the validity
 |  | ||||||
|              form.addControl(loginControlDir); |              form.addControl(loginControlDir); | ||||||
| 
 | 
 | ||||||
|           expect(formModel.find(["login"]).valid).toBe(false); |              // sync validators are set
 | ||||||
|         }); |              expect(formModel.hasError("required", ["login"])).toBe(true); | ||||||
|  |              expect(formModel.hasError("async", ["login"])).toBe(false); | ||||||
|  | 
 | ||||||
|  |              formModel.find(["login"]).updateValue("invalid value"); | ||||||
|  | 
 | ||||||
|  |              // sync validator passes, running async validators
 | ||||||
|  |              expect(formModel.pending).toBe(true); | ||||||
|  | 
 | ||||||
|  |              tick(); | ||||||
|  | 
 | ||||||
|  |              expect(formModel.hasError("required", ["login"])).toBe(false); | ||||||
|  |              expect(formModel.hasError("async", ["login"])).toBe(true); | ||||||
|  |            })); | ||||||
| 
 | 
 | ||||||
|         it("should write value to the DOM", () => { |         it("should write value to the DOM", () => { | ||||||
|           formModel.find(["login"]).updateValue("initValue"); |           formModel.find(["login"]).updateValue("initValue"); | ||||||
| @ -198,15 +223,27 @@ export function main() { | |||||||
|           } |           } | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         it("should set up validator", () => { |         it("should set up validator", fakeAsync(() => { | ||||||
|           var group = new NgControlGroup(form, [matchingPasswordsValidator]); |              var group = new NgControlGroup(form, [matchingPasswordsValidator], | ||||||
|  |                                             [asyncValidator('expected')]); | ||||||
|              group.name = "passwords"; |              group.name = "passwords"; | ||||||
|              form.addControlGroup(group); |              form.addControlGroup(group); | ||||||
| 
 | 
 | ||||||
|              formModel.find(["passwords", "password"]).updateValue("somePassword"); |              formModel.find(["passwords", "password"]).updateValue("somePassword"); | ||||||
|  |              formModel.find(["passwords", "passwordConfirm"]).updateValue("someOtherPassword"); | ||||||
| 
 | 
 | ||||||
|  |              // sync validators are set
 | ||||||
|              expect(formModel.hasError("differentPasswords", ["passwords"])).toEqual(true); |              expect(formModel.hasError("differentPasswords", ["passwords"])).toEqual(true); | ||||||
|         }); | 
 | ||||||
|  |              formModel.find(["passwords", "passwordConfirm"]).updateValue("somePassword"); | ||||||
|  | 
 | ||||||
|  |              // sync validators pass, running async validators
 | ||||||
|  |              expect(formModel.pending).toBe(true); | ||||||
|  | 
 | ||||||
|  |              tick(); | ||||||
|  | 
 | ||||||
|  |              expect(formModel.hasError("async", ["passwords"])).toBe(true); | ||||||
|  |            })); | ||||||
|       }); |       }); | ||||||
| 
 | 
 | ||||||
|       describe("removeControl", () => { |       describe("removeControl", () => { | ||||||
| @ -228,17 +265,24 @@ export function main() { | |||||||
|           expect((<any>loginControlDir.valueAccessor).writtenValue).toEqual("new value"); |           expect((<any>loginControlDir.valueAccessor).writtenValue).toEqual("new value"); | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|         it("should set up validator", () => { |         it("should set up a sync validator", () => { | ||||||
|           var formValidator = (c) => ({"custom": true}); |           var formValidator = (c) => ({"custom": true}); | ||||||
|           var f = new NgFormModel([formValidator]); |           var f = new NgFormModel([formValidator], []); | ||||||
|           f.form = formModel; |           f.form = formModel; | ||||||
|           f.onChanges({"form": formModel}); |           f.onChanges({"form": formModel}); | ||||||
| 
 | 
 | ||||||
|           // trigger validation
 |  | ||||||
|           formModel.controls["login"].updateValue(""); |  | ||||||
| 
 |  | ||||||
|           expect(formModel.errors).toEqual({"custom": true}); |           expect(formModel.errors).toEqual({"custom": true}); | ||||||
|         }); |         }); | ||||||
|  | 
 | ||||||
|  |         it("should set up an async validator", fakeAsync(() => { | ||||||
|  |              var f = new NgFormModel([], [asyncValidator("expected")]); | ||||||
|  |              f.form = formModel; | ||||||
|  |              f.onChanges({"form": formModel}); | ||||||
|  | 
 | ||||||
|  |              tick(); | ||||||
|  | 
 | ||||||
|  |              expect(formModel.errors).toEqual({"async": true}); | ||||||
|  |            })); | ||||||
|       }); |       }); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
| @ -249,13 +293,13 @@ export function main() { | |||||||
|       var personControlGroupDir; |       var personControlGroupDir; | ||||||
| 
 | 
 | ||||||
|       beforeEach(() => { |       beforeEach(() => { | ||||||
|         form = new NgForm([]); |         form = new NgForm([], []); | ||||||
|         formModel = form.form; |         formModel = form.form; | ||||||
| 
 | 
 | ||||||
|         personControlGroupDir = new NgControlGroup(form, []); |         personControlGroupDir = new NgControlGroup(form, [], []); | ||||||
|         personControlGroupDir.name = "person"; |         personControlGroupDir.name = "person"; | ||||||
| 
 | 
 | ||||||
|         loginControlDir = new NgControlName(personControlGroupDir, null, [defaultAccessor]); |         loginControlDir = new NgControlName(personControlGroupDir, null, null, [defaultAccessor]); | ||||||
|         loginControlDir.name = "login"; |         loginControlDir.name = "login"; | ||||||
|         loginControlDir.valueAccessor = new DummyControlValueAccessor(); |         loginControlDir.valueAccessor = new DummyControlValueAccessor(); | ||||||
|       }); |       }); | ||||||
| @ -301,16 +345,22 @@ export function main() { | |||||||
|         // should update the form's value and validity
 |         // should update the form's value and validity
 | ||||||
|       }); |       }); | ||||||
| 
 | 
 | ||||||
|       it("should set up validator", fakeAsync(() => { |       it("should set up sync validator", fakeAsync(() => { | ||||||
|            var formValidator = (c) => ({"custom": true}); |            var formValidator = (c) => ({"custom": true}); | ||||||
|            var f = new NgForm([formValidator]); |            var f = new NgForm([formValidator], []); | ||||||
|            f.addControlGroup(personControlGroupDir); |  | ||||||
|            f.addControl(loginControlDir); |  | ||||||
| 
 | 
 | ||||||
|            flushMicrotasks(); |            tick(); | ||||||
| 
 | 
 | ||||||
|            expect(f.form.errors).toEqual({"custom": true}); |            expect(f.form.errors).toEqual({"custom": true}); | ||||||
|          })); |          })); | ||||||
|  | 
 | ||||||
|  |       it("should set up async validator", fakeAsync(() => { | ||||||
|  |            var f = new NgForm([], [asyncValidator("expected")]); | ||||||
|  | 
 | ||||||
|  |            tick(); | ||||||
|  | 
 | ||||||
|  |            expect(f.form.errors).toEqual({"async": true}); | ||||||
|  |          })); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     describe("NgControlGroup", () => { |     describe("NgControlGroup", () => { | ||||||
| @ -320,9 +370,9 @@ export function main() { | |||||||
|       beforeEach(() => { |       beforeEach(() => { | ||||||
|         formModel = new ControlGroup({"login": new Control(null)}); |         formModel = new ControlGroup({"login": new Control(null)}); | ||||||
| 
 | 
 | ||||||
|         var parent = new NgFormModel([]); |         var parent = new NgFormModel([], []); | ||||||
|         parent.form = new ControlGroup({"group": formModel}); |         parent.form = new ControlGroup({"group": formModel}); | ||||||
|         controlGroupDir = new NgControlGroup(parent, []); |         controlGroupDir = new NgControlGroup(parent, [], []); | ||||||
|         controlGroupDir.name = "group"; |         controlGroupDir.name = "group"; | ||||||
|       }); |       }); | ||||||
| 
 | 
 | ||||||
| @ -353,7 +403,7 @@ export function main() { | |||||||
|       }; |       }; | ||||||
| 
 | 
 | ||||||
|       beforeEach(() => { |       beforeEach(() => { | ||||||
|         controlDir = new NgFormControl([Validators.required], [defaultAccessor]); |         controlDir = new NgFormControl([Validators.required], [], [defaultAccessor]); | ||||||
|         controlDir.valueAccessor = new DummyControlValueAccessor(); |         controlDir.valueAccessor = new DummyControlValueAccessor(); | ||||||
| 
 | 
 | ||||||
|         control = new Control(null); |         control = new Control(null); | ||||||
| @ -384,7 +434,8 @@ export function main() { | |||||||
|       var ngModel; |       var ngModel; | ||||||
| 
 | 
 | ||||||
|       beforeEach(() => { |       beforeEach(() => { | ||||||
|         ngModel = new NgModel([Validators.required], [defaultAccessor]); |         ngModel = | ||||||
|  |             new NgModel([Validators.required], [asyncValidator("expected")], [defaultAccessor]); | ||||||
|         ngModel.valueAccessor = new DummyControlValueAccessor(); |         ngModel.valueAccessor = new DummyControlValueAccessor(); | ||||||
|       }); |       }); | ||||||
| 
 | 
 | ||||||
| @ -400,14 +451,18 @@ export function main() { | |||||||
|         expect(ngModel.untouched).toBe(control.untouched); |         expect(ngModel.untouched).toBe(control.untouched); | ||||||
|       }); |       }); | ||||||
| 
 | 
 | ||||||
|       it("should set up validator", () => { |       it("should set up validator", fakeAsync(() => { | ||||||
|         expect(ngModel.control.valid).toBe(true); |  | ||||||
| 
 |  | ||||||
|            // this will add the required validator and recalculate the validity
 |            // this will add the required validator and recalculate the validity
 | ||||||
|            ngModel.onChanges({}); |            ngModel.onChanges({}); | ||||||
|  |            tick(); | ||||||
| 
 | 
 | ||||||
|         expect(ngModel.control.valid).toBe(false); |            expect(ngModel.control.errors).toEqual({"required": true}); | ||||||
|       }); | 
 | ||||||
|  |            ngModel.control.updateValue("someValue"); | ||||||
|  |            tick(); | ||||||
|  | 
 | ||||||
|  |            expect(ngModel.control.errors).toEqual({"async": true}); | ||||||
|  |          })); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     describe("NgControlName", () => { |     describe("NgControlName", () => { | ||||||
| @ -417,9 +472,9 @@ export function main() { | |||||||
|       beforeEach(() => { |       beforeEach(() => { | ||||||
|         formModel = new Control("name"); |         formModel = new Control("name"); | ||||||
| 
 | 
 | ||||||
|         var parent = new NgFormModel([]); |         var parent = new NgFormModel([], []); | ||||||
|         parent.form = new ControlGroup({"name": formModel}); |         parent.form = new ControlGroup({"name": formModel}); | ||||||
|         controlNameDir = new NgControlName(parent, [], [defaultAccessor]); |         controlNameDir = new NgControlName(parent, [], [], [defaultAccessor]); | ||||||
|         controlNameDir.name = "name"; |         controlNameDir.name = "name"; | ||||||
|       }); |       }); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -20,11 +20,13 @@ import { | |||||||
| 
 | 
 | ||||||
| import {DOM} from 'angular2/src/core/dom/dom_adapter'; | import {DOM} from 'angular2/src/core/dom/dom_adapter'; | ||||||
| import { | import { | ||||||
|  |   Input, | ||||||
|   Control, |   Control, | ||||||
|   ControlGroup, |   ControlGroup, | ||||||
|   ControlValueAccessor, |   ControlValueAccessor, | ||||||
|   FORM_DIRECTIVES, |   FORM_DIRECTIVES, | ||||||
|   NG_VALIDATORS, |   NG_VALIDATORS, | ||||||
|  |   NG_ASYNC_VALIDATORS, | ||||||
|   Provider, |   Provider, | ||||||
|   NgControl, |   NgControl, | ||||||
|   NgIf, |   NgIf, | ||||||
| @ -401,7 +403,7 @@ export function main() { | |||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     describe("validations", () => { |     describe("validations", () => { | ||||||
|       it("should use validators defined in html", |       it("should use sync validators defined in html", | ||||||
|          inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => { |          inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => { | ||||||
|            var form = new ControlGroup( |            var form = new ControlGroup( | ||||||
|                {"login": new Control(""), "min": new Control(""), "max": new Control("")}); |                {"login": new Control(""), "min": new Control(""), "max": new Control("")}); | ||||||
| @ -446,6 +448,35 @@ export function main() { | |||||||
|            }); |            }); | ||||||
|          })); |          })); | ||||||
| 
 | 
 | ||||||
|  |       it("should use async validators defined in the html", | ||||||
|  |          inject([TestComponentBuilder], fakeAsync((tcb: TestComponentBuilder) => { | ||||||
|  |                   var form = new ControlGroup({"login": new Control("")}); | ||||||
|  | 
 | ||||||
|  |                   var t = `<div [ng-form-model]="form">
 | ||||||
|  |                     <input type="text" ng-control="login" uniq-login-validator="expected"> | ||||||
|  |                  </div>`;
 | ||||||
|  | 
 | ||||||
|  |                   var rootTC; | ||||||
|  |                   tcb.overrideTemplate(MyComp, t).createAsync(MyComp).then((root) => rootTC = root); | ||||||
|  |                   tick(); | ||||||
|  | 
 | ||||||
|  |                   rootTC.debugElement.componentInstance.form = form; | ||||||
|  |                   rootTC.detectChanges(); | ||||||
|  | 
 | ||||||
|  |                   expect(form.pending).toEqual(true); | ||||||
|  | 
 | ||||||
|  |                   tick(100); | ||||||
|  | 
 | ||||||
|  |                   expect(form.hasError("uniqLogin", ["login"])).toEqual(true); | ||||||
|  | 
 | ||||||
|  |                   var input = rootTC.debugElement.query(By.css("input")); | ||||||
|  |                   input.nativeElement.value = "expected"; | ||||||
|  |                   dispatchEvent(input.nativeElement, "change"); | ||||||
|  |                   tick(100); | ||||||
|  | 
 | ||||||
|  |                   expect(form.valid).toEqual(true); | ||||||
|  |                 }))); | ||||||
|  | 
 | ||||||
|       it("should use sync validators defined in the model", |       it("should use sync validators defined in the model", | ||||||
|          inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => { |          inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => { | ||||||
|            var form = new ControlGroup({"login": new Control("aa", Validators.required)}); |            var form = new ControlGroup({"login": new Control("aa", Validators.required)}); | ||||||
| @ -961,10 +992,10 @@ class MyInput implements ControlValueAccessor { | |||||||
| 
 | 
 | ||||||
| function uniqLoginAsyncValidator(expectedValue: string) { | function uniqLoginAsyncValidator(expectedValue: string) { | ||||||
|   return (c) => { |   return (c) => { | ||||||
|     var e = new EventEmitter(); |     var completer = PromiseWrapper.completer(); | ||||||
|     var res = (c.value == expectedValue) ? null : {"uniqLogin": true}; |     var res = (c.value == expectedValue) ? null : {"uniqLogin": true}; | ||||||
|     PromiseWrapper.scheduleMicrotask(() => ObservableWrapper.callNext(e, res)); |     completer.resolve(res); | ||||||
|     return e; |     return completer.promise; | ||||||
|   }; |   }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -979,10 +1010,31 @@ function loginIsEmptyGroupValidator(c: ControlGroup) { | |||||||
| class LoginIsEmptyValidator { | class LoginIsEmptyValidator { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @Directive({ | ||||||
|  |   selector: '[uniq-login-validator]', | ||||||
|  |   providers: [ | ||||||
|  |     new Provider(NG_ASYNC_VALIDATORS, | ||||||
|  |                  {useExisting: forwardRef(() => UniqLoginValidator), multi: true}) | ||||||
|  |   ] | ||||||
|  | }) | ||||||
|  | class UniqLoginValidator implements Validator { | ||||||
|  |   @Input('uniq-login-validator') expected; | ||||||
|  | 
 | ||||||
|  |   validate(c) { return uniqLoginAsyncValidator(this.expected)(c); } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| @Component({ | @Component({ | ||||||
|   selector: "my-comp", |   selector: "my-comp", | ||||||
|   template: '', |   template: '', | ||||||
|   directives: [FORM_DIRECTIVES, WrappedValue, MyInput, NgIf, NgFor, LoginIsEmptyValidator] |   directives: [ | ||||||
|  |     FORM_DIRECTIVES, | ||||||
|  |     WrappedValue, | ||||||
|  |     MyInput, | ||||||
|  |     NgIf, | ||||||
|  |     NgFor, | ||||||
|  |     LoginIsEmptyValidator, | ||||||
|  |     UniqLoginValidator | ||||||
|  |   ] | ||||||
| }) | }) | ||||||
| class MyComp { | class MyComp { | ||||||
|   form: any; |   form: any; | ||||||
|  | |||||||
| @ -15,23 +15,24 @@ import { | |||||||
| } from 'angular2/testing_internal'; | } from 'angular2/testing_internal'; | ||||||
| import {ControlGroup, Control, ControlArray, Validators} from 'angular2/core'; | import {ControlGroup, Control, ControlArray, Validators} from 'angular2/core'; | ||||||
| import {isPresent, CONST_EXPR} from 'angular2/src/core/facade/lang'; | import {isPresent, CONST_EXPR} from 'angular2/src/core/facade/lang'; | ||||||
| import {EventEmitter, TimerWrapper, ObservableWrapper} from 'angular2/src/core/facade/async'; | import {PromiseWrapper} from 'angular2/src/core/facade/promise'; | ||||||
|  | import {TimerWrapper, ObservableWrapper} from 'angular2/src/core/facade/async'; | ||||||
| import {IS_DART} from '../../platform'; | import {IS_DART} from '../../platform'; | ||||||
| import {PromiseWrapper} from "angular2/src/core/facade/promise"; |  | ||||||
| 
 | 
 | ||||||
| export function main() { | export function main() { | ||||||
|   function asyncValidator(expected, timeouts = CONST_EXPR({})) { |   function asyncValidator(expected, timeouts = CONST_EXPR({})) { | ||||||
|     return (c) => { |     return (c) => { | ||||||
|       var e = new EventEmitter(); |       var completer = PromiseWrapper.completer(); | ||||||
|       var t = isPresent(timeouts[c.value]) ? timeouts[c.value] : 0; |       var t = isPresent(timeouts[c.value]) ? timeouts[c.value] : 0; | ||||||
|       var res = c.value != expected ? {"async": true} : null; |       var res = c.value != expected ? {"async": true} : null; | ||||||
| 
 | 
 | ||||||
|       if (t == 0) { |       if (t == 0) { | ||||||
|         PromiseWrapper.scheduleMicrotask(() => { ObservableWrapper.callNext(e, res); }); |         completer.resolve(res); | ||||||
|       } else { |       } else { | ||||||
|         TimerWrapper.setTimeout(() => { ObservableWrapper.callNext(e, res); }, t); |         TimerWrapper.setTimeout(() => { completer.resolve(res); }, t); | ||||||
|       } |       } | ||||||
|       return e; | 
 | ||||||
|  |       return completer.promise; | ||||||
|     }; |     }; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -819,6 +819,7 @@ var NG_ALL = [ | |||||||
|   'LowerCasePipe', |   'LowerCasePipe', | ||||||
|   'LowerCasePipe.transform()', |   'LowerCasePipe.transform()', | ||||||
|   'NG_VALIDATORS', |   'NG_VALIDATORS', | ||||||
|  |   'NG_ASYNC_VALIDATORS', | ||||||
|   'NgClass', |   'NgClass', | ||||||
|   'NgClass.doCheck()', |   'NgClass.doCheck()', | ||||||
|   'NgClass.initialClasses=', |   'NgClass.initialClasses=', | ||||||
| @ -837,6 +838,7 @@ var NG_ALL = [ | |||||||
|   'NgControl.untouched', |   'NgControl.untouched', | ||||||
|   'NgControl.valid', |   'NgControl.valid', | ||||||
|   'NgControl.validator', |   'NgControl.validator', | ||||||
|  |   'NgControl.asyncValidator', | ||||||
|   'NgControl.value', |   'NgControl.value', | ||||||
|   'NgControl.valueAccessor', |   'NgControl.valueAccessor', | ||||||
|   'NgControl.valueAccessor=', |   'NgControl.valueAccessor=', | ||||||
| @ -857,6 +859,7 @@ var NG_ALL = [ | |||||||
|   'NgControlGroup.valid', |   'NgControlGroup.valid', | ||||||
|   'NgControlGroup.value', |   'NgControlGroup.value', | ||||||
|   'NgControlGroup.validator', |   'NgControlGroup.validator', | ||||||
|  |   'NgControlGroup.asyncValidator', | ||||||
|   'NgControlStatus', |   'NgControlStatus', | ||||||
|   'NgControlStatus.ngClassDirty', |   'NgControlStatus.ngClassDirty', | ||||||
|   'NgControlStatus.ngClassInvalid', |   'NgControlStatus.ngClassInvalid', | ||||||
| @ -884,6 +887,7 @@ var NG_ALL = [ | |||||||
|   'NgControlName.update=', |   'NgControlName.update=', | ||||||
|   'NgControlName.valid', |   'NgControlName.valid', | ||||||
|   'NgControlName.validator', |   'NgControlName.validator', | ||||||
|  |   'NgControlName.asyncValidator', | ||||||
|   'NgControlName.value', |   'NgControlName.value', | ||||||
|   'NgControlName.valueAccessor', |   'NgControlName.valueAccessor', | ||||||
|   'NgControlName.valueAccessor=', |   'NgControlName.valueAccessor=', | ||||||
| @ -941,6 +945,7 @@ var NG_ALL = [ | |||||||
|   'NgFormControl.update=', |   'NgFormControl.update=', | ||||||
|   'NgFormControl.valid', |   'NgFormControl.valid', | ||||||
|   'NgFormControl.validator', |   'NgFormControl.validator', | ||||||
|  |   'NgFormControl.asyncValidator', | ||||||
|   'NgFormControl.value', |   'NgFormControl.value', | ||||||
|   'NgFormControl.valueAccessor', |   'NgFormControl.valueAccessor', | ||||||
|   'NgFormControl.valueAccessor=', |   'NgFormControl.valueAccessor=', | ||||||
| @ -996,6 +1001,7 @@ var NG_ALL = [ | |||||||
|   'NgModel.update=', |   'NgModel.update=', | ||||||
|   'NgModel.valid', |   'NgModel.valid', | ||||||
|   'NgModel.validator', |   'NgModel.validator', | ||||||
|  |   'NgModel.asyncValidator', | ||||||
|   'NgModel.value', |   'NgModel.value', | ||||||
|   'NgModel.valueAccessor', |   'NgModel.valueAccessor', | ||||||
|   'NgModel.valueAccessor=', |   'NgModel.valueAccessor=', | ||||||
| @ -1223,6 +1229,7 @@ var NG_ALL = [ | |||||||
|   'UrlResolver', |   'UrlResolver', | ||||||
|   'UrlResolver.resolve()', |   'UrlResolver.resolve()', | ||||||
|   'Validators#compose()', |   'Validators#compose()', | ||||||
|  |   'Validators#composeAsync()', | ||||||
|   'Validators#nullValidator()', |   'Validators#nullValidator()', | ||||||
|   'Validators#required()', |   'Validators#required()', | ||||||
|   'Validators#minLength()', |   'Validators#minLength()', | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user