X Tutup
Skip to content

Commit 31c12af

Browse files
committed
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(); } }
1 parent cf449dd commit 31c12af

File tree

14 files changed

+249
-101
lines changed

14 files changed

+249
-101
lines changed

modules/angular2/src/core/forms.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export {
3333
SelectControlValueAccessor
3434
} from './forms/directives/select_control_value_accessor';
3535
export {FORM_DIRECTIVES} from './forms/directives';
36-
export {NG_VALIDATORS, Validators} from './forms/validators';
36+
export {NG_VALIDATORS, NG_ASYNC_VALIDATORS, Validators} from './forms/validators';
3737
export {
3838
RequiredValidator,
3939
MinLengthValidator,

modules/angular2/src/core/forms/directives/ng_control.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export abstract class NgControl extends AbstractControlDirective {
1313
valueAccessor: ControlValueAccessor = null;
1414

1515
get validator(): Function { return unimplemented(); }
16+
get asyncValidator(): Function { return unimplemented(); }
1617

1718
abstract viewToModelUpdate(newValue: any): void;
1819
}

modules/angular2/src/core/forms/directives/ng_control_group.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import {ListWrapper} from 'angular2/src/core/facade/collection';
55
import {CONST_EXPR} from 'angular2/src/core/facade/lang';
66

77
import {ControlContainer} from './control_container';
8-
import {controlPath} from './shared';
8+
import {controlPath, composeValidators, composeAsyncValidators} from './shared';
99
import {ControlGroup} from '../model';
1010
import {Form} from './form_interface';
11-
import {Validators, NG_VALIDATORS} from '../validators';
11+
import {Validators, NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators';
1212

1313
const controlGroupProvider =
1414
CONST_EXPR(new Provider(ControlContainer, {useExisting: forwardRef(() => NgControlGroup)}));
@@ -72,13 +72,11 @@ export class NgControlGroup extends ControlContainer implements OnInit,
7272
/** @internal */
7373
_parent: ControlContainer;
7474

75-
private _validators: Function[];
76-
7775
constructor(@Host() @SkipSelf() parent: ControlContainer,
78-
@Optional() @Inject(NG_VALIDATORS) validators: Function[]) {
76+
@Optional() @Inject(NG_VALIDATORS) private _validators: any[],
77+
@Optional() @Inject(NG_ASYNC_VALIDATORS) private _asyncValidators: any[]) {
7978
super();
8079
this._parent = parent;
81-
this._validators = validators;
8280
}
8381

8482
onInit(): void { this.formDirective.addControlGroup(this); }
@@ -100,5 +98,7 @@ export class NgControlGroup extends ControlContainer implements OnInit,
10098
*/
10199
get formDirective(): Form { return this._parent.formDirective; }
102100

103-
get validator(): Function { return Validators.compose(this._validators); }
101+
get validator(): Function { return composeValidators(this._validators); }
102+
103+
get asyncValidator(): Function { return composeAsyncValidators(this._asyncValidators); }
104104
}

modules/angular2/src/core/forms/directives/ng_control_name.ts

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,15 @@ import {forwardRef, Host, SkipSelf, Provider, Inject, Optional} from 'angular2/s
88
import {ControlContainer} from './control_container';
99
import {NgControl} from './ng_control';
1010
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
11-
import {controlPath, composeValidators, isPropertyUpdated, selectValueAccessor} from './shared';
11+
import {
12+
controlPath,
13+
composeValidators,
14+
composeAsyncValidators,
15+
isPropertyUpdated,
16+
selectValueAccessor
17+
} from './shared';
1218
import {Control} from '../model';
13-
import {Validators, NG_VALIDATORS} from '../validators';
19+
import {Validators, NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators';
1420

1521

1622
const controlNameBinding =
@@ -81,21 +87,18 @@ const controlNameBinding =
8187
export class NgControlName extends NgControl implements OnChanges,
8288
OnDestroy {
8389
/** @internal */
84-
_parent: ControlContainer;
8590
update = new EventEmitter();
8691
model: any;
8792
viewModel: any;
88-
private _validator: Function;
89-
/** @internal */
90-
_added = false;
93+
private _added = false;
9194

92-
constructor(@Host() @SkipSelf() parent: ControlContainer,
93-
@Optional() @Inject(NG_VALIDATORS) validators:
95+
constructor(@Host() @SkipSelf() private _parent: ControlContainer,
96+
@Optional() @Inject(NG_VALIDATORS) private _validators:
97+
/* Array<Validator|Function> */ any[],
98+
@Optional() @Inject(NG_ASYNC_VALIDATORS) private _asyncValidators:
9499
/* Array<Validator|Function> */ any[],
95100
@Optional() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[]) {
96101
super();
97-
this._parent = parent;
98-
this._validator = composeValidators(validators);
99102
this.valueAccessor = selectValueAccessor(this, valueAccessors);
100103
}
101104

@@ -121,7 +124,9 @@ export class NgControlName extends NgControl implements OnChanges,
121124

122125
get formDirective(): any { return this._parent.formDirective; }
123126

124-
get validator(): Function { return this._validator; }
127+
get validator(): Function { return composeValidators(this._validators); }
128+
129+
get asyncValidator(): Function { return composeAsyncValidators(this._asyncValidators); }
125130

126131
get control(): Control { return this.formDirective.getControl(this); }
127132
}

modules/angular2/src/core/forms/directives/ng_form.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import {Form} from './form_interface';
1313
import {NgControlGroup} from './ng_control_group';
1414
import {ControlContainer} from './control_container';
1515
import {AbstractControl, ControlGroup, Control} from '../model';
16-
import {setUpControl, setUpControlGroup} from './shared';
17-
import {Validators, NG_VALIDATORS} from '../validators';
16+
import {setUpControl, setUpControlGroup, composeValidators, composeAsyncValidators} from './shared';
17+
import {Validators, NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators';
1818

1919
const formDirectiveProvider =
2020
CONST_EXPR(new Provider(ControlContainer, {useExisting: forwardRef(() => NgForm)}));
@@ -91,9 +91,11 @@ export class NgForm extends ControlContainer implements Form {
9191
form: ControlGroup;
9292
ngSubmit = new EventEmitter();
9393

94-
constructor(@Optional() @Inject(NG_VALIDATORS) validators: Function[]) {
94+
constructor(@Optional() @Inject(NG_VALIDATORS) validators: any[],
95+
@Optional() @Inject(NG_ASYNC_VALIDATORS) asyncValidators: any[]) {
9596
super();
96-
this.form = new ControlGroup({}, null, Validators.compose(validators));
97+
this.form = new ControlGroup({}, null, composeValidators(validators),
98+
composeAsyncValidators(asyncValidators));
9799
}
98100

99101
get formDirective(): Form { return this; }

modules/angular2/src/core/forms/directives/ng_form_control.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,15 @@ import {Query, Directive} from 'angular2/src/core/metadata';
77
import {forwardRef, Provider, Inject, Optional} from 'angular2/src/core/di';
88
import {NgControl} from './ng_control';
99
import {Control} from '../model';
10-
import {Validators, NG_VALIDATORS} from '../validators';
10+
import {Validators, NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators';
1111
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
12-
import {setUpControl, composeValidators, isPropertyUpdated, selectValueAccessor} from './shared';
12+
import {
13+
setUpControl,
14+
composeValidators,
15+
composeAsyncValidators,
16+
isPropertyUpdated,
17+
selectValueAccessor
18+
} from './shared';
1319

1420
const formControlBinding =
1521
CONST_EXPR(new Provider(NgControl, {useExisting: forwardRef(() => NgFormControl)}));
@@ -73,13 +79,13 @@ export class NgFormControl extends NgControl implements OnChanges {
7379
update = new EventEmitter();
7480
model: any;
7581
viewModel: any;
76-
private _validator: Function;
7782

78-
constructor(@Optional() @Inject(NG_VALIDATORS) validators:
83+
constructor(@Optional() @Inject(NG_VALIDATORS) private _validators:
84+
/* Array<Validator|Function> */ any[],
85+
@Optional() @Inject(NG_ASYNC_VALIDATORS) private _asyncValidators:
7986
/* Array<Validator|Function> */ any[],
8087
@Optional() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[]) {
8188
super();
82-
this._validator = composeValidators(validators);
8389
this.valueAccessor = selectValueAccessor(this, valueAccessors);
8490
}
8591

@@ -96,7 +102,9 @@ export class NgFormControl extends NgControl implements OnChanges {
96102

97103
get path(): string[] { return []; }
98104

99-
get validator(): Function { return this._validator; }
105+
get validator(): Function { return composeValidators(this._validators); }
106+
107+
get asyncValidator(): Function { return composeAsyncValidators(this._asyncValidators); }
100108

101109
get control(): Control { return this.form; }
102110

modules/angular2/src/core/forms/directives/ng_form_model.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import {NgControlGroup} from './ng_control_group';
1111
import {ControlContainer} from './control_container';
1212
import {Form} from './form_interface';
1313
import {Control, ControlGroup} from '../model';
14-
import {setUpControl, setUpControlGroup} from './shared';
15-
import {Validators, NG_VALIDATORS} from '../validators';
14+
import {setUpControl, setUpControlGroup, composeValidators, composeAsyncValidators} from './shared';
15+
import {Validators, NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators';
1616

1717
const formDirectiveProvider =
1818
CONST_EXPR(new Provider(ControlContainer, {useExisting: forwardRef(() => NgFormModel)}));
@@ -102,17 +102,21 @@ export class NgFormModel extends ControlContainer implements Form,
102102
form: ControlGroup = null;
103103
directives: NgControl[] = [];
104104
ngSubmit = new EventEmitter();
105-
private _validators: Function[];
106105

107-
constructor(@Optional() @Inject(NG_VALIDATORS) validators: Function[]) {
106+
constructor(@Optional() @Inject(NG_VALIDATORS) private _validators: any[],
107+
@Optional() @Inject(NG_ASYNC_VALIDATORS) private _asyncValidators: any[]) {
108108
super();
109-
this._validators = validators;
110109
}
111110

112111
onChanges(changes: {[key: string]: SimpleChange}): void {
113112
if (StringMapWrapper.contains(changes, "form")) {
114-
var c = Validators.compose(this._validators);
115-
this.form.validator = Validators.compose([this.form.validator, c]);
113+
var sync = composeValidators(this._validators);
114+
this.form.validator = Validators.compose([this.form.validator, sync]);
115+
116+
var async = composeAsyncValidators(this._asyncValidators);
117+
this.form.asyncValidator = Validators.composeAsync([this.form.asyncValidator, async]);
118+
119+
this.form.updateValueAndValidity({onlySelf: true, emitEvent: false});
116120
}
117121

118122
this._updateDomValue();

modules/angular2/src/core/forms/directives/ng_model.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,14 @@ import {forwardRef, Provider, Inject, Optional} from 'angular2/src/core/di';
77
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
88
import {NgControl} from './ng_control';
99
import {Control} from '../model';
10-
import {Validators, NG_VALIDATORS} from '../validators';
11-
import {setUpControl, isPropertyUpdated, selectValueAccessor, composeValidators} from './shared';
10+
import {Validators, NG_VALIDATORS, NG_ASYNC_VALIDATORS} from '../validators';
11+
import {
12+
setUpControl,
13+
isPropertyUpdated,
14+
selectValueAccessor,
15+
composeValidators,
16+
composeAsyncValidators
17+
} from './shared';
1218

1319
const formControlBinding =
1420
CONST_EXPR(new Provider(NgControl, {useExisting: forwardRef(() => NgModel)}));
@@ -49,13 +55,11 @@ export class NgModel extends NgControl implements OnChanges {
4955
update = new EventEmitter();
5056
model: any;
5157
viewModel: any;
52-
private _validator: Function;
5358

54-
constructor(@Optional() @Inject(NG_VALIDATORS) validators:
55-
/* Array<Validator|Function> */ any[],
59+
constructor(@Optional() @Inject(NG_VALIDATORS) private _validators: any[],
60+
@Optional() @Inject(NG_ASYNC_VALIDATORS) private _asyncValidators: any[],
5661
@Optional() @Inject(NG_VALUE_ACCESSOR) valueAccessors: ControlValueAccessor[]) {
5762
super();
58-
this._validator = composeValidators(validators);
5963
this.valueAccessor = selectValueAccessor(this, valueAccessors);
6064
}
6165

@@ -76,7 +80,9 @@ export class NgModel extends NgControl implements OnChanges {
7680

7781
get path(): string[] { return []; }
7882

79-
get validator(): Function { return this._validator; }
83+
get validator(): Function { return composeValidators(this._validators); }
84+
85+
get asyncValidator(): Function { return composeAsyncValidators(this._asyncValidators); }
8086

8187
viewToModelUpdate(newValue: any): void {
8288
this.viewModel = newValue;

modules/angular2/src/core/forms/directives/shared.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export function setUpControl(control: Control, dir: NgControl): void {
2929
if (isBlank(dir.valueAccessor)) _throwError(dir, "No value accessor for");
3030

3131
control.validator = Validators.compose([control.validator, dir.validator]);
32+
control.asyncValidator = Validators.composeAsync([control.asyncValidator, dir.asyncValidator]);
3233
dir.valueAccessor.writeValue(control.value);
3334

3435
// view -> model
@@ -48,6 +49,7 @@ export function setUpControl(control: Control, dir: NgControl): void {
4849
export function setUpControlGroup(control: ControlGroup, dir: NgControlGroup) {
4950
if (isBlank(control)) _throwError(dir, "Cannot find control");
5051
control.validator = Validators.compose([control.validator, dir.validator]);
52+
control.asyncValidator = Validators.composeAsync([control.asyncValidator, dir.asyncValidator]);
5153
}
5254

5355
function _throwError(dir: AbstractControlDirective, message: string): void {
@@ -61,8 +63,12 @@ export function setProperty(renderer: Renderer, elementRef: ElementRef, propName
6163
}
6264

6365
export function composeValidators(validators: /* Array<Validator|Function> */ any[]): Function {
64-
return isPresent(validators) ? Validators.compose(validators.map(normalizeValidator)) :
65-
Validators.nullValidator;
66+
return isPresent(validators) ? Validators.compose(validators.map(normalizeValidator)) : null;
67+
}
68+
69+
export function composeAsyncValidators(
70+
validators: /* Array<Validator|Function> */ any[]): Function {
71+
return isPresent(validators) ? Validators.composeAsync(validators.map(normalizeValidator)) : null;
6672
}
6773

6874
export function isPropertyUpdated(changes: {[key: string]: any}, viewModel: any): boolean {

modules/angular2/src/core/forms/model.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,9 @@ export abstract class AbstractControl {
142142
if (isPresent(this.asyncValidator)) {
143143
this._status = PENDING;
144144
this._cancelExistingSubscription();
145+
var obs = ObservableWrapper.fromPromise(this.asyncValidator(this));
145146
this._asyncValidationSubscription =
146-
ObservableWrapper.subscribe(this.asyncValidator(this), res => this.setErrors(res));
147+
ObservableWrapper.subscribe(obs, res => this.setErrors(res));
147148
}
148149
}
149150

0 commit comments

Comments
 (0)
X Tutup