refactor(forms): refactored forms to user Query to get html validators
This commit is contained in:
parent
85b8a15374
commit
4d1ed509e3
|
@ -38,8 +38,6 @@ export class BaseQueryList<T> {
|
|||
removeCallback(callback) { ListWrapper.remove(this._callbacks, callback); }
|
||||
|
||||
get length() { return this._results.length; }
|
||||
|
||||
get first() { return ListWrapper.first(this._results); }
|
||||
|
||||
get last() { return ListWrapper.last(this._results); }
|
||||
}
|
||||
|
|
|
@ -184,6 +184,8 @@ class ListWrapper {
|
|||
|
||||
bool isListLikeIterable(obj) => obj is Iterable;
|
||||
|
||||
List<T> iterableToList(Iterable<T> ii) => ii.toList();
|
||||
|
||||
void iterateListLike(iter, fn(item)) {
|
||||
assert(iter is Iterable);
|
||||
for (var item in iter) {
|
||||
|
|
|
@ -253,7 +253,13 @@ export function iterateListLike(obj, fn: Function) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function iterableToList<T>(ii:Iterable<T>):List<T> {
|
||||
var res = [];
|
||||
for (var i of ii) {
|
||||
res.push(i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Safari and Internet Explorer do not support the iterable parameter to the
|
||||
// Set constructor. We work around that by manually adding the items.
|
||||
|
|
|
@ -24,7 +24,7 @@ export {ControlValueAccessor} from './directives/control_value_accessor';
|
|||
export {DefaultValueAccessor} from './directives/default_value_accessor';
|
||||
export {CheckboxControlValueAccessor} from './directives/checkbox_value_accessor';
|
||||
export {SelectControlValueAccessor} from './directives/select_control_value_accessor';
|
||||
export {NgRequiredValidator} from './directives/validators';
|
||||
export {NgValidator, NgRequiredValidator} from './directives/validators';
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import {ControlValueAccessor} from './control_value_accessor';
|
||||
import {Validators} from '../validators';
|
||||
import {Control} from '../model';
|
||||
|
||||
/**
|
||||
|
@ -12,11 +11,10 @@ import {Control} from '../model';
|
|||
export class NgControl {
|
||||
name: string = null;
|
||||
valueAccessor: ControlValueAccessor = null;
|
||||
validator: Function;
|
||||
|
||||
get validator(): Function { return null; }
|
||||
get path(): List<string> { return null; }
|
||||
get control(): Control { return null; }
|
||||
constructor() { this.validator = Validators.nullValidator; }
|
||||
|
||||
viewToModelUpdate(newValue: any): void {}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import {CONST_EXPR} from 'angular2/src/facade/lang';
|
||||
import {EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
|
||||
import {List, StringMapWrapper, StringMap} from 'angular2/src/facade/collection';
|
||||
import {Directive, Ancestor, onDestroy, onChange} from 'angular2/angular2';
|
||||
|
||||
import {Directive, Ancestor, onDestroy, onChange, Query, QueryList} from 'angular2/angular2';
|
||||
import {forwardRef, Binding, Inject} from 'angular2/di';
|
||||
|
||||
import {ControlContainer} from './control_container';
|
||||
import {NgControl} from './ng_control';
|
||||
import {controlPath} from './shared';
|
||||
import {NgValidator} from './validators';
|
||||
import {controlPath, composeNgValidator} from './shared';
|
||||
import {Control} from '../model';
|
||||
|
||||
const controlNameBinding =
|
||||
|
@ -82,13 +84,17 @@ export class NgControlName extends NgControl {
|
|||
_parent: ControlContainer;
|
||||
ngModel: EventEmitter;
|
||||
model: any;
|
||||
ngValidators: QueryList<NgValidator>;
|
||||
_added: boolean;
|
||||
|
||||
constructor(@Ancestor() _parent: ControlContainer) {
|
||||
// Scope the query once https://github.com/angular/angular/issues/2603 is fixed
|
||||
constructor(@Ancestor() parent: ControlContainer,
|
||||
@Query(NgValidator) ngValidators: QueryList<NgValidator>) {
|
||||
super();
|
||||
this._parent = _parent;
|
||||
this._parent = parent;
|
||||
this.ngModel = new EventEmitter();
|
||||
this._added = false;
|
||||
this.ngValidators = ngValidators;
|
||||
}
|
||||
|
||||
onChange(c: StringMap<string, any>) {
|
||||
|
@ -101,7 +107,6 @@ export class NgControlName extends NgControl {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
onDestroy() { this.formDirective.removeControl(this); }
|
||||
|
||||
viewToModelUpdate(newValue: any): void { ObservableWrapper.callNext(this.ngModel, newValue); }
|
||||
|
@ -111,4 +116,6 @@ export class NgControlName extends NgControl {
|
|||
get formDirective(): any { return this._parent.formDirective; }
|
||||
|
||||
get control(): Control { return this.formDirective.getControl(this); }
|
||||
|
||||
get validator(): Function { return composeNgValidator(this.ngValidators); }
|
||||
}
|
|
@ -2,12 +2,13 @@ import {CONST_EXPR} from 'angular2/src/facade/lang';
|
|||
import {StringMapWrapper} from 'angular2/src/facade/collection';
|
||||
import {EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
|
||||
|
||||
import {Directive, Ancestor, onChange} from 'angular2/angular2';
|
||||
import {Directive, Ancestor, onChange, Query, QueryList} from 'angular2/angular2';
|
||||
import {forwardRef, Binding} from 'angular2/di';
|
||||
|
||||
import {NgControl} from './ng_control';
|
||||
import {Control} from '../model';
|
||||
import {setUpControl} from './shared';
|
||||
import {NgValidator} from './validators';
|
||||
import {setUpControl, composeNgValidator} from './shared';
|
||||
|
||||
const formControlBinding =
|
||||
CONST_EXPR(new Binding(NgControl, {toAlias: forwardRef(() => NgFormControl)}));
|
||||
|
@ -72,11 +73,14 @@ export class NgFormControl extends NgControl {
|
|||
ngModel: EventEmitter;
|
||||
_added: boolean;
|
||||
model: any;
|
||||
ngValidators: QueryList<NgValidator>;
|
||||
|
||||
constructor() {
|
||||
// Scope the query once https://github.com/angular/angular/issues/2603 is fixed
|
||||
constructor(@Query(NgValidator) ngValidators: QueryList<NgValidator>) {
|
||||
super();
|
||||
this.ngModel = new EventEmitter();
|
||||
this._added = false;
|
||||
this.ngValidators = ngValidators;
|
||||
}
|
||||
|
||||
onChange(c) {
|
||||
|
@ -90,9 +94,11 @@ export class NgFormControl extends NgControl {
|
|||
}
|
||||
}
|
||||
|
||||
get path(): List<string> { return []; }
|
||||
|
||||
get control(): Control { return this.form; }
|
||||
|
||||
get path(): List<string> { return []; }
|
||||
get validator(): Function { return composeNgValidator(this.ngValidators); }
|
||||
|
||||
viewToModelUpdate(newValue: any): void { ObservableWrapper.callNext(this.ngModel, newValue); }
|
||||
}
|
||||
|
|
|
@ -2,12 +2,13 @@ import {CONST_EXPR} from 'angular2/src/facade/lang';
|
|||
import {EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
|
||||
import {StringMapWrapper} from 'angular2/src/facade/collection';
|
||||
|
||||
import {Directive, Ancestor, onChange} from 'angular2/angular2';
|
||||
import {Directive, Ancestor, onChange, QueryList, Query} from 'angular2/angular2';
|
||||
import {forwardRef, Binding} from 'angular2/di';
|
||||
|
||||
import {NgControl} from './ng_control';
|
||||
import {Control} from '../model';
|
||||
import {setUpControl} from './shared';
|
||||
import {NgValidator} from './validators';
|
||||
import {setUpControl, composeNgValidator} from './shared';
|
||||
|
||||
const formControlBinding = CONST_EXPR(new Binding(NgControl, {toAlias: forwardRef(() => NgModel)}));
|
||||
|
||||
|
@ -42,13 +43,20 @@ export class NgModel extends NgControl {
|
|||
_added = false;
|
||||
ngModel = new EventEmitter();
|
||||
model: any;
|
||||
ngValidators: QueryList<NgValidator>;
|
||||
|
||||
// Scope the query once https://github.com/angular/angular/issues/2603 is fixed
|
||||
constructor(@Query(NgValidator) ngValidators: QueryList<NgValidator>) {
|
||||
super();
|
||||
this.ngValidators = ngValidators;
|
||||
}
|
||||
|
||||
onChange(c) {
|
||||
if (!this._added) {
|
||||
setUpControl(this._control, this);
|
||||
this.control.updateValidity();
|
||||
this._control.updateValidity();
|
||||
this._added = true;
|
||||
};
|
||||
}
|
||||
|
||||
if (StringMapWrapper.contains(c, "model")) {
|
||||
this._control.updateValue(this.model);
|
||||
|
@ -59,5 +67,7 @@ export class NgModel extends NgControl {
|
|||
|
||||
get path(): List<string> { return []; }
|
||||
|
||||
get validator(): Function { return composeNgValidator(this.ngValidators); }
|
||||
|
||||
viewToModelUpdate(newValue: any): void { ObservableWrapper.callNext(this.ngModel, newValue); }
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {ListWrapper, iterableToList} from 'angular2/src/facade/collection';
|
||||
import {isBlank, BaseException} from 'angular2/src/facade/lang';
|
||||
|
||||
import {ControlContainer} from './control_container';
|
||||
import {NgControl} from './ng_control';
|
||||
import {NgValidator} from './validators';
|
||||
import {Control} from '../model';
|
||||
import {Validators} from '../validators';
|
||||
import {Renderer, ElementRef} from 'angular2/angular2';
|
||||
import {Renderer, ElementRef, QueryList} from 'angular2/angular2';
|
||||
|
||||
|
||||
export function controlPath(name, parent: ControlContainer) {
|
||||
|
@ -35,6 +36,11 @@ export function setUpControl(c: Control, dir: NgControl) {
|
|||
dir.valueAccessor.registerOnTouched(() => c.markAsTouched());
|
||||
}
|
||||
|
||||
export function composeNgValidator(ngValidators: QueryList<NgValidator>): Function {
|
||||
if (isBlank(ngValidators)) return Validators.nullValidator;
|
||||
return Validators.compose(iterableToList(ngValidators).map(v => v.validator));
|
||||
}
|
||||
|
||||
function _throwError(dir: NgControl, message: string): void {
|
||||
var path = ListWrapper.join(dir.path, " -> ");
|
||||
throw new BaseException(`${message} '${path}'`);
|
||||
|
@ -43,5 +49,5 @@ function _throwError(dir: NgControl, message: string): void {
|
|||
export function setProperty(renderer: Renderer, elementRef: ElementRef, propName: string,
|
||||
propValue: any) {
|
||||
renderer.setElementProperty(elementRef.parentView.render, elementRef.boundElementIndex, propName,
|
||||
propValue);
|
||||
propValue);
|
||||
}
|
|
@ -1,10 +1,19 @@
|
|||
import {forwardRef, Binding} from 'angular2/di';
|
||||
import {CONST_EXPR} from 'angular2/src/facade/lang';
|
||||
import {Directive} from '../../../angular2';
|
||||
import {Validators} from '../validators';
|
||||
import {NgControl} from '../directives';
|
||||
|
||||
@Directive({selector: '[required][ng-control],[required][ng-form-control],[required][ng-model]'})
|
||||
export class NgRequiredValidator {
|
||||
constructor(c: NgControl) {
|
||||
c.validator = Validators.compose([c.validator, Validators.required]);
|
||||
}
|
||||
export class NgValidator {
|
||||
get validator(): Function { throw "Is not implemented"; }
|
||||
}
|
||||
|
||||
const requiredValidatorBinding =
|
||||
CONST_EXPR(new Binding(NgValidator, {toAlias: forwardRef(() => NgRequiredValidator)}));
|
||||
|
||||
@Directive({
|
||||
selector: '[required][ng-control],[required][ng-form-control],[required][ng-model]',
|
||||
hostInjector: [requiredValidatorBinding]
|
||||
})
|
||||
export class NgRequiredValidator extends NgValidator {
|
||||
get validator(): Function { return Validators.required; }
|
||||
}
|
||||
|
|
|
@ -13,6 +13,9 @@ import {
|
|||
AsyncTestCompleter,
|
||||
inject
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {QueryList} from 'angular2/angular2';
|
||||
|
||||
import {
|
||||
ControlGroup,
|
||||
Control,
|
||||
|
@ -22,7 +25,9 @@ import {
|
|||
ControlValueAccessor,
|
||||
Validators,
|
||||
NgForm,
|
||||
NgFormControl
|
||||
NgModel,
|
||||
NgFormControl,
|
||||
NgRequiredValidator
|
||||
} from 'angular2/forms';
|
||||
|
||||
class DummyControlValueAccessor implements ControlValueAccessor {
|
||||
|
@ -46,14 +51,14 @@ export function main() {
|
|||
formModel = new ControlGroup({"login": new Control(null)});
|
||||
form.form = formModel;
|
||||
|
||||
loginControlDir = new NgControlName(form);
|
||||
loginControlDir = new NgControlName(form, new QueryList<any>());
|
||||
loginControlDir.name = "login";
|
||||
loginControlDir.valueAccessor = new DummyControlValueAccessor();
|
||||
});
|
||||
|
||||
describe("addControl", () => {
|
||||
it("should throw when no control found", () => {
|
||||
var dir = new NgControlName(form);
|
||||
var dir = new NgControlName(form, null);
|
||||
dir.name = "invalidName";
|
||||
|
||||
expect(() => form.addControl(dir))
|
||||
|
@ -61,7 +66,7 @@ export function main() {
|
|||
});
|
||||
|
||||
it("should throw when no value accessor", () => {
|
||||
var dir = new NgControlName(form);
|
||||
var dir = new NgControlName(form, null);
|
||||
dir.name = "login";
|
||||
|
||||
expect(() => form.addControl(dir))
|
||||
|
@ -69,7 +74,7 @@ export function main() {
|
|||
});
|
||||
|
||||
it("should set up validator", () => {
|
||||
loginControlDir.validator = Validators.required;
|
||||
loginControlDir.ngValidators.reset([new NgRequiredValidator()]);
|
||||
|
||||
expect(formModel.find(["login"]).valid).toBe(true);
|
||||
|
||||
|
@ -127,7 +132,7 @@ export function main() {
|
|||
personControlGroupDir = new NgControlGroup(form);
|
||||
personControlGroupDir.name = "person";
|
||||
|
||||
loginControlDir = new NgControlName(personControlGroupDir);
|
||||
loginControlDir = new NgControlName(personControlGroupDir, null);
|
||||
loginControlDir.name = "login";
|
||||
loginControlDir.valueAccessor = new DummyControlValueAccessor();
|
||||
});
|
||||
|
@ -168,7 +173,7 @@ export function main() {
|
|||
var control;
|
||||
|
||||
beforeEach(() => {
|
||||
controlDir = new NgFormControl();
|
||||
controlDir = new NgFormControl(new QueryList<any>());
|
||||
controlDir.valueAccessor = new DummyControlValueAccessor();
|
||||
|
||||
control = new Control(null);
|
||||
|
@ -176,7 +181,7 @@ export function main() {
|
|||
});
|
||||
|
||||
it("should set up validator", () => {
|
||||
controlDir.validator = Validators.required;
|
||||
controlDir.ngValidators.reset([new NgRequiredValidator()]);
|
||||
|
||||
expect(control.valid).toBe(true);
|
||||
|
||||
|
@ -186,5 +191,25 @@ export function main() {
|
|||
expect(control.valid).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("NgModel", () => {
|
||||
var ngModel;
|
||||
|
||||
beforeEach(() => {
|
||||
ngModel = new NgModel(new QueryList<any>());
|
||||
ngModel.valueAccessor = new DummyControlValueAccessor();
|
||||
});
|
||||
|
||||
it("should set up validator", () => {
|
||||
ngModel.ngValidators.reset([new NgRequiredValidator()]);
|
||||
|
||||
expect(ngModel.control.valid).toBe(true);
|
||||
|
||||
// this will add the required validator and recalculate the validity
|
||||
ngModel.onChange({});
|
||||
|
||||
expect(ngModel.control.valid).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue