refactor(forms): wrapped all validators into the Validator class

This commit is contained in:
vsavkin 2015-03-19 14:21:40 -07:00
parent 41b53e71e1
commit a12dc7d75a
8 changed files with 69 additions and 72 deletions

View File

@ -4,7 +4,7 @@ import {DOM} from 'angular2/src/dom/dom_adapter';
import {isBlank, isPresent, isString, CONST} from 'angular2/src/facade/lang';
import {StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection';
import {ControlGroup, Control} from './model';
import * as validators from './validators';
import {Validators} from './validators';
@CONST()
export class ControlValueAccessor {
@ -79,7 +79,7 @@ export class ControlDirective {
this._el = el;
this.controlName = null;
this.type = null;
this.validator = validators.nullValidator;
this.validator = Validators.nullValidator;
}
// TODO: vsavkin this should be moved into the constructor once static bindings
@ -92,7 +92,7 @@ export class ControlDirective {
this._groupDirective.addDirective(this);
var c = this._control();
c.validator = validators.compose([c.validator, this.validator]);
c.validator = Validators.compose([c.validator, this.validator]);
if (isBlank(this.valueAccessor)) {
this.valueAccessor = controlValueAccessorFor(this.type);

View File

@ -1,6 +1,6 @@
import {isPresent} from 'angular2/src/facade/lang';
import {StringMap, StringMapWrapper} from 'angular2/src/facade/collection';
import {nullValidator, controlGroupValidator} from './validators';
import {Validators} from './validators';
export const VALID = "VALID";
export const INVALID = "INVALID";
@ -26,7 +26,7 @@ export class AbstractControl {
_parent:ControlGroup;
validator:Function;
constructor(validator:Function = nullValidator) {
constructor(validator:Function) {
this.validator = validator;
this._updateNeeded = true;
this._pristine = true;
@ -76,7 +76,7 @@ export class AbstractControl {
}
export class Control extends AbstractControl {
constructor(value:any, validator:Function = nullValidator) {
constructor(value:any, validator:Function = Validators.nullValidator) {
super(validator);
this._value = value;
}
@ -101,7 +101,7 @@ export class ControlGroup extends AbstractControl {
controls;
optionals;
constructor(controls, optionals = null, validator:Function = controlGroupValidator) {
constructor(controls, optionals = null, validator:Function = Validators.group) {
super(validator);
this.controls = controls;
this.optionals = isPresent(optionals) ? optionals : {};

View File

@ -1,13 +1,12 @@
import {Decorator} from 'angular2/angular2';
import {ControlDirective} from 'angular2/forms';
import * as validators from 'angular2/forms';
import {ControlDirective, Validators} from 'angular2/forms';
@Decorator({
selector: '[required]'
})
export class RequiredValidatorDirective {
constructor(c:ControlDirective) {
c.validator = validators.compose([c.validator, validators.required]);
c.validator = Validators.compose([c.validator, Validators.required]);
}
}

View File

@ -3,30 +3,31 @@ import {List, ListWrapper, StringMapWrapper} from 'angular2/src/facade/collectio
import * as modelModule from './model';
export function required(c:modelModule.Control) {
return isBlank(c.value) || c.value == "" ? {"required" : true} : null;
}
export class Validators {
static required(c:modelModule.Control) {
return isBlank(c.value) || c.value == "" ? {"required": true} : null;
}
export function nullValidator(c:modelModule.Control) {
static nullValidator(c:modelModule.Control) {
return null;
}
}
export function compose(validators:List<Function>):Function {
return function(c:modelModule.Control) {
static compose(validators:List<Function>):Function {
return function (c:modelModule.Control) {
var res = ListWrapper.reduce(validators, (res, validator) => {
var errors = validator(c);
return isPresent(errors) ? StringMapWrapper.merge(res, errors) : res;
}, {});
return StringMapWrapper.isEmpty(res) ? null : res;
}
}
}
export function controlGroupValidator(c:modelModule.ControlGroup) {
static group(c:modelModule.ControlGroup) {
var res = {};
StringMapWrapper.forEach(c.controls, (control, name) => {
if (c.contains(name) && isPresent(control.errors)) {
StringMapWrapper.forEach(control.errors, (value, error) => {
if (! StringMapWrapper.contains(res, error)) {
if (!StringMapWrapper.contains(res, error)) {
res[error] = [];
}
ListWrapper.push(res[error], control);
@ -34,4 +35,5 @@ export function controlGroupValidator(c:modelModule.ControlGroup) {
}
});
return StringMapWrapper.isEmpty(res) ? null : res;
}
}

View File

@ -1,6 +1,5 @@
import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach, el} from 'angular2/test_lib';
import {Control, FormBuilder} from 'angular2/forms';
import * as validations from 'angular2/forms';
import {Control, FormBuilder, Validators} from 'angular2/forms';
export function main() {
describe("Form Builder", () => {
@ -21,21 +20,21 @@ export function main() {
it("should create controls from an array", () => {
var g = b.group({
"login": ["some value"],
"password": ["some value", validations.required]
"password": ["some value", Validators.required]
});
expect(g.controls["login"].value).toEqual("some value");
expect(g.controls["password"].value).toEqual("some value");
expect(g.controls["password"].validator).toEqual(validations.required);
expect(g.controls["password"].validator).toEqual(Validators.required);
});
it("should use controls", () => {
var g = b.group({
"login": b.control("some value", validations.required)
"login": b.control("some value", Validators.required)
});
expect(g.controls["login"].value).toEqual("some value");
expect(g.controls["login"].validator).toBe(validations.required);
expect(g.controls["login"].validator).toBe(Validators.required);
});
it("should create groups with optional controls", () => {
@ -49,17 +48,17 @@ export function main() {
it("should create groups with a custom validator", () => {
var g = b.group({
"login": "some value"
}, {"validator": validations.nullValidator});
}, {"validator": Validators.nullValidator});
expect(g.validator).toBe(validations.nullValidator);
expect(g.validator).toBe(Validators.nullValidator);
});
it("should use default validators when no validators are provided", () => {
var g = b.group({
"login": "some value"
});
expect(g.controls["login"].validator).toBe(validations.nullValidator);
expect(g.validator).toBe(validations.controlGroupValidator);
expect(g.controls["login"].validator).toBe(Validators.nullValidator);
expect(g.validator).toBe(Validators.group);
});
});
}

View File

@ -31,9 +31,7 @@ import {Injector} from 'angular2/di';
import {Component, Decorator, Template} from 'angular2/angular2';
import {ControlGroupDirective, ControlDirective, Control, ControlGroup, OptionalControl,
ControlValueAccessor, RequiredValidatorDirective} from 'angular2/forms';
import * as validators from 'angular2/src/forms/validators';
ControlValueAccessor, RequiredValidatorDirective, Validators} from 'angular2/forms';
export function main() {
function detectChanges(view) {
@ -261,7 +259,7 @@ export function main() {
}));
it("should use validators defined in the model", inject([AsyncTestCompleter], (async) => {
var form = new ControlGroup({"login": new Control("aa", validators.required)});
var form = new ControlGroup({"login": new Control("aa", Validators.required)});
var ctx = new MyComp(form);
var t = `<div [control-group]="form">

View File

@ -1,24 +1,23 @@
import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach, el} from 'angular2/test_lib';
import {ControlGroup, Control, OptionalControl} from 'angular2/forms';
import * as validations from 'angular2/forms';
import {ControlGroup, Control, OptionalControl, Validators} from 'angular2/forms';
export function main() {
describe("Form Model", () => {
describe("Control", () => {
describe("validator", () => {
it("should run validator with the initial value", () => {
var c = new Control("value", validations.required);
var c = new Control("value", Validators.required);
expect(c.valid).toEqual(true);
});
it("should rerun the validator when the value changes", () => {
var c = new Control("value", validations.required);
var c = new Control("value", Validators.required);
c.updateValue(null);
expect(c.valid).toEqual(false);
});
it("should return errors", () => {
var c = new Control(null, validations.required);
var c = new Control(null, Validators.required);
expect(c.errors).toEqual({"required" : true});
});
});
@ -83,7 +82,7 @@ export function main() {
describe("validator", () => {
it("should run the validator with the initial value (valid)", () => {
var g = new ControlGroup({
"one": new Control('value', validations.required)
"one": new Control('value', Validators.required)
});
expect(g.valid).toEqual(true);
@ -92,7 +91,7 @@ export function main() {
});
it("should run the validator with the initial value (invalid)", () => {
var one = new Control(null, validations.required);
var one = new Control(null, Validators.required);
var g = new ControlGroup({"one": one});
expect(g.valid).toEqual(false);
@ -101,7 +100,7 @@ export function main() {
});
it("should run the validator with the value changes", () => {
var c = new Control(null, validations.required);
var c = new Control(null, Validators.required);
var g = new ControlGroup({"one": c});
c.updateValue("some value");
@ -174,10 +173,10 @@ export function main() {
expect(group.value).toEqual({"required" : "requiredValue", "optional" : "optionalValue"});
});
it("should not run validations on an inactive component", () => {
it("should not run Validators on an inactive component", () => {
var group = new ControlGroup({
"required": new Control("requiredValue", validations.required),
"optional": new Control("", validations.required)
"required": new Control("requiredValue", Validators.required),
"optional": new Control("", Validators.required)
}, {
"optional": false
});

View File

@ -1,5 +1,5 @@
import {ddescribe, describe, it, iit, xit, expect, beforeEach, afterEach, el} from 'angular2/test_lib';
import {ControlGroup, Control, required, compose, controlGroupValidator, nullValidator} from 'angular2/forms';
import {ControlGroup, Control, Validators} from 'angular2/forms';
export function main() {
function validator(key:string, error:any){
@ -13,31 +13,31 @@ export function main() {
describe("Validators", () => {
describe("required", () => {
it("should error on an empty string", () => {
expect(required(new Control(""))).toEqual({"required" : true});
expect(Validators.required(new Control(""))).toEqual({"required" : true});
});
it("should error on null", () => {
expect(required(new Control(null))).toEqual({"required" : true});
expect(Validators.required(new Control(null))).toEqual({"required" : true});
});
it("should not error on a non-empty string", () => {
expect(required(new Control("not empty"))).toEqual(null);
expect(Validators.required(new Control("not empty"))).toEqual(null);
});
});
describe("compose", () => {
it("should collect errors from all the validators", () => {
var c = compose([validator("a", true), validator("b", true)]);
var c = Validators.compose([validator("a", true), validator("b", true)]);
expect(c(new Control(""))).toEqual({"a" : true, "b" : true});
});
it("should run validators left to right", () => {
var c = compose([validator("a", 1), validator("a", 2)]);
var c = Validators.compose([validator("a", 1), validator("a", 2)]);
expect(c(new Control(""))).toEqual({"a" : 2});
});
it("should return null when no errors", () => {
var c = compose([nullValidator, nullValidator]);
var c = Validators.compose([Validators.nullValidator, Validators.nullValidator]);
expect(c(new Control(""))).toEqual(null);
});
});
@ -48,7 +48,7 @@ export function main() {
var two = new Control("one", validator("b", true));
var g = new ControlGroup({"one" : one, "two" : two});
expect(controlGroupValidator(g)).toEqual({
expect(Validators.group(g)).toEqual({
"a" : [one],
"b" : [two]
});
@ -59,7 +59,7 @@ export function main() {
var two = new Control("two");
var g = new ControlGroup({"one" : one, "two" : two});
expect(controlGroupValidator(g)).toEqual({
expect(Validators.group(g)).toEqual({
"a": [one]
});
});
@ -69,7 +69,7 @@ export function main() {
"one" : new Control("one")
});
expect(controlGroupValidator(g)).toEqual(null);
expect(Validators.group(g)).toEqual(null);
});
});
});