feat(forms): added hasError and getError methods to all controls

This commit is contained in:
vsavkin 2015-06-05 14:28:19 -07:00
parent 8923103c3b
commit 1a4d23742b
2 changed files with 226 additions and 173 deletions

View File

@ -1,4 +1,4 @@
import {StringWrapper, isPresent} from 'angular2/src/facade/lang';
import {StringWrapper, isPresent, isBlank} from 'angular2/src/facade/lang';
import {Observable, EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
import {StringMap, StringMapWrapper, ListWrapper, List} from 'angular2/src/facade/collection';
import {Validators} from './validators';
@ -21,6 +21,24 @@ export function isControl(c: Object): boolean {
return c instanceof AbstractControl;
}
function _find(c: AbstractControl, path: List<string | number>| string) {
if (isBlank(path)) return null;
if (!(path instanceof List)) {
path = StringWrapper.split(<string>path, new RegExp("/"));
}
if (ListWrapper.isEmpty(path)) return null;
return ListWrapper.reduce(<List<string | number>>path, (v, name) => {
if (v instanceof ControlGroup) {
return isPresent(v.controls[name]) ? v.controls[name] : null;
} else if (v instanceof ControlArray) {
var index = <number>name;
return isPresent(v.at(index)) ? v.at(index) : null;
} else {
return null;
}
}, c);
}
/**
* Omitting from external API doc as this is really an abstract internal concept.
@ -31,7 +49,7 @@ export class AbstractControl {
_errors: StringMap<string, any>;
_pristine: boolean;
_touched: boolean;
_parent: any; /* ControlGroup | ControlArray */
_parent: ControlGroup | ControlArray;
validator: Function;
_valueChanges: EventEmitter;
@ -78,6 +96,7 @@ export class AbstractControl {
this._errors = this.validator(this);
this._status = isPresent(this._errors) ? INVALID : VALID;
if (isPresent(this._parent) && !onlySelf) {
this._parent.updateValidity({onlySelf: onlySelf});
}
@ -101,6 +120,21 @@ export class AbstractControl {
}
}
find(path: List<string | number>| string): AbstractControl { return _find(this, path); }
getError(errorCode: string, path: List<string> = null) {
var c = this.find(path);
if (isPresent(c) && isPresent(c._errors)) {
return StringMapWrapper.get(c._errors, errorCode);
} else {
return null;
}
}
hasError(errorCode: string, path: List<string> = null) {
return isPresent(this.getError(errorCode, path));
}
_updateValue(): void {}
}
@ -168,7 +202,10 @@ export class ControlGroup extends AbstractControl {
this.updateValidity({onlySelf: true});
}
addControl(name: string, c: AbstractControl) { this.controls[name] = c; }
addControl(name: string, c: AbstractControl) {
this.controls[name] = c;
c.setParent(this);
}
removeControl(name: string) { StringMapWrapper.delete(this.controls, name); }
@ -187,18 +224,6 @@ export class ControlGroup extends AbstractControl {
return c && this._included(controlName);
}
find(path: string | List<string>): AbstractControl {
if (!(path instanceof List)) {
path = StringWrapper.split(<string>path, new RegExp("/"));
}
return ListWrapper.reduce(
<List<string>>path, (v, name) => v instanceof ControlGroup && isPresent(v.controls[name]) ?
v.controls[name] :
null,
this);
}
_setParentForControls() {
StringMapWrapper.forEach(this.controls, (control, name) => { control.setParent(this); });
}

View File

@ -148,25 +148,6 @@ export function main() {
});
});
describe("find", () => {
var g;
beforeEach(() => {
g = new ControlGroup(
{"one": new Control("111"), "nested": new ControlGroup({"two": new Control("222")})});
});
it("should return a control if it is present", () => {
expect(g.find(["nested", "two"]).value).toEqual("222");
expect(g.find(["one"]).value).toEqual("111");
expect(g.find("nested/two").value).toEqual("222");
expect(g.find("one").value).toEqual("111");
});
it("should return null otherwise", () => {
expect(g.find("invalid")).toBeNull();
expect(g.find("one/invalid")).toBeNull();
});
});
describe("validator", () => {
it("should run the validator with the initial value (valid)", () => {
@ -349,6 +330,22 @@ export function main() {
// hard to test without hacking zones
}));
});
describe("getError", () => {
it("should return the error when it is present", () => {
var c = new Control("", Validators.required);
var g = new ControlGroup({"one": c});
expect(g.getError("required", ["one"])).toEqual(true);
});
it("should return null otherwise", () => {
var c = new Control("not empty", Validators.required);
var g = new ControlGroup({"one": c});
expect(g.getError("required", ["one"])).toEqual(null);
expect(g.getError("required", ["invalid"])).toEqual(null);
});
});
});
});
describe("ControlArray", () => {
@ -495,8 +492,7 @@ export function main() {
a.removeAt(1);
}));
it("should fire an event when a control is added",
inject([AsyncTestCompleter], (async) => {
it("should fire an event when a control is added", inject([AsyncTestCompleter], (async) => {
a.removeAt(1);
ObservableWrapper.subscribe(a.valueChanges, (value) => {
@ -508,6 +504,38 @@ export function main() {
}));
});
});
describe("find", () => {
it("should return null when path is null", () => {
var g = new ControlGroup({});
expect(g.find(null)).toEqual(null);
});
it("should return null when path is empty", () => {
var g = new ControlGroup({});
expect(g.find([])).toEqual(null);
});
it("should return null when path is invalid", () => {
var g = new ControlGroup({});
expect(g.find(["one", "two"])).toEqual(null);
});
it("should return a child of a control group", () => {
var g = new ControlGroup(
{"one": new Control("111"), "nested": new ControlGroup({"two": new Control("222")})});
expect(g.find(["nested", "two"]).value).toEqual("222");
expect(g.find(["one"]).value).toEqual("111");
expect(g.find("nested/two").value).toEqual("222");
expect(g.find("one").value).toEqual("111");
});
it("should return an element of an array", () => {
var g = new ControlGroup({"array": new ControlArray([new Control("111")])});
expect(g.find(["array", 0]).value).toEqual("111");
});
});
});
}