feat(forms): support adding validators to ControlGroup via template

Closes #4954
This commit is contained in:
vsavkin
2015-10-27 14:36:13 -07:00
committed by Victor Savkin
parent f98faf0702
commit 758062807a
9 changed files with 137 additions and 30 deletions

View File

@ -21,4 +21,6 @@ export class AbstractControlDirective {
get touched(): boolean { return isPresent(this.control) ? this.control.touched : null; }
get untouched(): boolean { return isPresent(this.control) ? this.control.untouched : null; }
get path(): string[] { return null; }
}

View File

@ -14,7 +14,6 @@ export class NgControl extends AbstractControlDirective {
valueAccessor: ControlValueAccessor = null;
get validator(): Function { return null; }
get path(): string[] { return null; }
viewToModelUpdate(newValue: any): void {}
}

View File

@ -1,6 +1,6 @@
import {OnInit, OnDestroy} from 'angular2/lifecycle_hooks';
import {Directive} from 'angular2/src/core/metadata';
import {Inject, Host, SkipSelf, forwardRef, Provider} from 'angular2/src/core/di';
import {Optional, Inject, Host, SkipSelf, forwardRef, Provider} from 'angular2/src/core/di';
import {ListWrapper} from 'angular2/src/core/facade/collection';
import {CONST_EXPR} from 'angular2/src/core/facade/lang';
@ -8,6 +8,7 @@ import {ControlContainer} from './control_container';
import {controlPath} from './shared';
import {ControlGroup} from '../model';
import {Form} from './form_interface';
import {Validators, NG_VALIDATORS} from '../validators';
const controlGroupBinding =
CONST_EXPR(new Provider(ControlContainer, {useExisting: forwardRef(() => NgControlGroup)}));
@ -60,9 +61,14 @@ export class NgControlGroup extends ControlContainer implements OnInit,
OnDestroy {
/** @internal */
_parent: ControlContainer;
constructor(@Host() @SkipSelf() _parent: ControlContainer) {
private _validators: Function[];
constructor(@Host() @SkipSelf() parent: ControlContainer,
@Optional() @Inject(NG_VALIDATORS) validators: Function[]) {
super();
this._parent = _parent;
this._parent = parent;
this._validators = validators;
}
onInit(): void { this.formDirective.addControlGroup(this); }
@ -74,4 +80,6 @@ export class NgControlGroup extends ControlContainer implements OnInit,
get path(): string[] { return controlPath(this.name, this._parent); }
get formDirective(): Form { return this._parent.formDirective; }
get validator(): Function { return Validators.compose(this._validators); }
}

View File

@ -7,13 +7,14 @@ import {
import {StringMapWrapper, ListWrapper} from 'angular2/src/core/facade/collection';
import {isPresent, isBlank, CONST_EXPR} from 'angular2/src/core/facade/lang';
import {Directive} from 'angular2/src/core/metadata';
import {forwardRef, Provider} from 'angular2/src/core/di';
import {forwardRef, Provider, Optional, Inject} from 'angular2/src/core/di';
import {NgControl} from './ng_control';
import {Form} from './form_interface';
import {NgControlGroup} from './ng_control_group';
import {ControlContainer} from './control_container';
import {AbstractControl, ControlGroup, Control} from '../model';
import {setUpControl} from './shared';
import {setUpControl, setUpControlGroup} from './shared';
import {Validators, NG_VALIDATORS} from '../validators';
const formDirectiveProvider =
CONST_EXPR(new Provider(ControlContainer, {useExisting: forwardRef(() => NgForm)}));
@ -87,9 +88,14 @@ const formDirectiveProvider =
exportAs: 'form'
})
export class NgForm extends ControlContainer implements Form {
form: ControlGroup = new ControlGroup({});
form: ControlGroup;
ngSubmit = new EventEmitter();
constructor(@Optional() @Inject(NG_VALIDATORS) validators: Function[]) {
super();
this.form = new ControlGroup({}, null, Validators.compose(validators));
}
get formDirective(): Form { return this; }
get control(): ControlGroup { return this.form; }
@ -124,6 +130,7 @@ export class NgForm extends ControlContainer implements Form {
this._later(_ => {
var container = this._findContainer(dir.path);
var group = new ControlGroup({});
setUpControlGroup(group, dir);
container.addControl(dir.name, group);
group.updateValueAndValidity({emitEvent: false});
});

View File

@ -1,16 +1,18 @@
import {CONST_EXPR} from 'angular2/src/core/facade/lang';
import {ListWrapper} from 'angular2/src/core/facade/collection';
import {ListWrapper, StringMapWrapper} from 'angular2/src/core/facade/collection';
import {ObservableWrapper, EventEmitter} from 'angular2/src/core/facade/async';
import {SimpleChange} from 'angular2/src/core/change_detection';
import {OnChanges} from 'angular2/lifecycle_hooks';
import {Directive} from 'angular2/src/core/metadata';
import {forwardRef, Provider} from 'angular2/src/core/di';
import {forwardRef, Provider, Inject, Optional} from 'angular2/src/core/di';
import {NgControl} from './ng_control';
import {NgControlGroup} from './ng_control_group';
import {ControlContainer} from './control_container';
import {Form} from './form_interface';
import {Control, ControlGroup} from '../model';
import {setUpControl} from './shared';
import {setUpControl, setUpControlGroup} from './shared';
import {Validators, NG_VALIDATORS} from '../validators';
const formDirectiveProvider =
CONST_EXPR(new Provider(ControlContainer, {useExisting: forwardRef(() => NgFormModel)}));
@ -100,8 +102,21 @@ export class NgFormModel extends ControlContainer implements Form,
form: ControlGroup = null;
directives: NgControl[] = [];
ngSubmit = new EventEmitter();
private _validators: Function[];
onChanges(_): void { this._updateDomValue(); }
constructor(@Optional() @Inject(NG_VALIDATORS) validators: Function[]) {
super();
this._validators = validators;
}
onChanges(changes: {[key: string]: SimpleChange}): void {
if (StringMapWrapper.contains(changes, "form")) {
var c = Validators.compose(this._validators);
this.form.validator = Validators.compose([this.form.validator, c]);
}
this._updateDomValue();
}
get formDirective(): Form { return this; }
@ -120,7 +135,11 @@ export class NgFormModel extends ControlContainer implements Form,
removeControl(dir: NgControl): void { ListWrapper.remove(this.directives, dir); }
addControlGroup(dir: NgControlGroup) {}
addControlGroup(dir: NgControlGroup) {
var ctrl: any = this.form.find(dir.path);
setUpControlGroup(ctrl, dir);
ctrl.updateValueAndValidity({emitEvent: false});
}
removeControlGroup(dir: NgControlGroup) {}

View File

@ -4,7 +4,9 @@ import {BaseException, WrappedException} from 'angular2/src/core/facade/exceptio
import {ControlContainer} from './control_container';
import {NgControl} from './ng_control';
import {Control} from '../model';
import {AbstractControlDirective} from './abstract_control_directive';
import {NgControlGroup} from './ng_control_group';
import {Control, ControlGroup} from '../model';
import {Validators} from '../validators';
import {ControlValueAccessor} from './control_value_accessor';
import {ElementRef, QueryList} from 'angular2/src/core/linker';
@ -42,7 +44,12 @@ export function setUpControl(control: Control, dir: NgControl): void {
dir.valueAccessor.registerOnTouched(() => control.markAsTouched());
}
function _throwError(dir: NgControl, message: string): void {
export function setUpControlGroup(control: ControlGroup, dir: NgControlGroup) {
if (isBlank(control)) _throwError(dir, "Cannot find control");
control.validator = Validators.compose([control.validator, dir.validator]);
}
function _throwError(dir: AbstractControlDirective, message: string): void {
var path = dir.path.join(" -> ");
throw new BaseException(`${message} '${path}'`);
}