feat(forms/validators): pattern validator
Adding static pattern validation method to Validators Adding a directive for the pattern validator Applying clang-format rules to modified files Updating public api spec for new pattern validator Adding pattern validator to public api guard tool For #5411 Closes #5561
This commit is contained in:
parent
f6a8d04c32
commit
38cb526f60
|
@ -37,6 +37,7 @@ export {
|
||||||
RequiredValidator,
|
RequiredValidator,
|
||||||
MinLengthValidator,
|
MinLengthValidator,
|
||||||
MaxLengthValidator,
|
MaxLengthValidator,
|
||||||
|
PatternValidator,
|
||||||
Validator
|
Validator
|
||||||
} from './forms/directives/validators';
|
} from './forms/directives/validators';
|
||||||
export {FormBuilder} from './forms/form_builder';
|
export {FormBuilder} from './forms/form_builder';
|
||||||
|
|
|
@ -14,7 +14,12 @@ import {
|
||||||
SelectControlValueAccessor,
|
SelectControlValueAccessor,
|
||||||
NgSelectOption
|
NgSelectOption
|
||||||
} from './directives/select_control_value_accessor';
|
} from './directives/select_control_value_accessor';
|
||||||
import {RequiredValidator, MinLengthValidator, MaxLengthValidator} from './directives/validators';
|
import {
|
||||||
|
RequiredValidator,
|
||||||
|
MinLengthValidator,
|
||||||
|
MaxLengthValidator,
|
||||||
|
PatternValidator
|
||||||
|
} from './directives/validators';
|
||||||
|
|
||||||
export {NgControlName} from './directives/ng_control_name';
|
export {NgControlName} from './directives/ng_control_name';
|
||||||
export {NgFormControl} from './directives/ng_form_control';
|
export {NgFormControl} from './directives/ng_form_control';
|
||||||
|
@ -34,7 +39,12 @@ export {
|
||||||
SelectControlValueAccessor,
|
SelectControlValueAccessor,
|
||||||
NgSelectOption
|
NgSelectOption
|
||||||
} from './directives/select_control_value_accessor';
|
} from './directives/select_control_value_accessor';
|
||||||
export {RequiredValidator, MinLengthValidator, MaxLengthValidator} from './directives/validators';
|
export {
|
||||||
|
RequiredValidator,
|
||||||
|
MinLengthValidator,
|
||||||
|
MaxLengthValidator,
|
||||||
|
PatternValidator
|
||||||
|
} from './directives/validators';
|
||||||
export {NgControl} from './directives/ng_control';
|
export {NgControl} from './directives/ng_control';
|
||||||
export {ControlValueAccessor} from './directives/control_value_accessor';
|
export {ControlValueAccessor} from './directives/control_value_accessor';
|
||||||
|
|
||||||
|
@ -73,5 +83,6 @@ export const FORM_DIRECTIVES: Type[] = CONST_EXPR([
|
||||||
|
|
||||||
RequiredValidator,
|
RequiredValidator,
|
||||||
MinLengthValidator,
|
MinLengthValidator,
|
||||||
MaxLengthValidator
|
MaxLengthValidator,
|
||||||
|
PatternValidator
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -100,3 +100,32 @@ export class MaxLengthValidator implements Validator {
|
||||||
|
|
||||||
validate(c: Control): {[key: string]: any} { return this._validator(c); }
|
validate(c: Control): {[key: string]: any} { return this._validator(c); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Directive that adds the `pattern` validator to any controls marked with the
|
||||||
|
* `pattern` attribute, via the {@link NG_VALIDATORS} binding. Uses attribute value
|
||||||
|
* as the regex to validate Control value against. Follows pattern attribute
|
||||||
|
* semantics; i.e. regex must match entire Control value.
|
||||||
|
*
|
||||||
|
* ### Example
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* <input [ngControl]="fullName" pattern="[a-zA-Z ]*">
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
const PATTERN_VALIDATOR = CONST_EXPR(
|
||||||
|
new Provider(NG_VALIDATORS, {useExisting: forwardRef(() => PatternValidator), multi: true}));
|
||||||
|
@Directive({
|
||||||
|
selector: '[pattern][ngControl],[pattern][ngFormControl],[pattern][ngModel]',
|
||||||
|
providers: [PATTERN_VALIDATOR]
|
||||||
|
})
|
||||||
|
export class PatternValidator implements Validator {
|
||||||
|
private _validator: Function;
|
||||||
|
|
||||||
|
constructor(@Attribute("pattern") pattern: string) {
|
||||||
|
this._validator = Validators.pattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
validate(c: Control): {[key: string]: any} { return this._validator(c); }
|
||||||
|
}
|
||||||
|
|
|
@ -75,6 +75,19 @@ export class Validators {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validator that requires a control to match a regex to its value.
|
||||||
|
*/
|
||||||
|
static pattern(pattern: string): Function {
|
||||||
|
return (control: modelModule.Control): {[key: string]: any} => {
|
||||||
|
if (isPresent(Validators.required(control))) return null;
|
||||||
|
let regex = new RegExp(`^${pattern}$`);
|
||||||
|
let v: string = control.value;
|
||||||
|
return regex.test(v) ? null :
|
||||||
|
{"pattern": {"requiredPattern": `^${pattern}$`, "actualValue": v}};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* No-op validator.
|
* No-op validator.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -66,12 +66,28 @@ export function main() {
|
||||||
it("should not error on valid strings",
|
it("should not error on valid strings",
|
||||||
() => { expect(Validators.maxLength(2)(new Control("aa"))).toEqual(null); });
|
() => { expect(Validators.maxLength(2)(new Control("aa"))).toEqual(null); });
|
||||||
|
|
||||||
it("should error on short strings", () => {
|
it("should error on long strings", () => {
|
||||||
expect(Validators.maxLength(2)(new Control("aaa")))
|
expect(Validators.maxLength(2)(new Control("aaa")))
|
||||||
.toEqual({"maxlength": {"requiredLength": 2, "actualLength": 3}});
|
.toEqual({"maxlength": {"requiredLength": 2, "actualLength": 3}});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("pattern", () => {
|
||||||
|
it("should not error on an empty string",
|
||||||
|
() => { expect(Validators.pattern("[a-zA-Z ]*")(new Control(""))).toEqual(null); });
|
||||||
|
|
||||||
|
it("should not error on null",
|
||||||
|
() => { expect(Validators.pattern("[a-zA-Z ]*")(new Control(null))).toEqual(null); });
|
||||||
|
|
||||||
|
it("should not error on valid strings",
|
||||||
|
() => { expect(Validators.pattern("[a-zA-Z ]*")(new Control("aaAA"))).toEqual(null); });
|
||||||
|
|
||||||
|
it("should error on failure to match string", () => {
|
||||||
|
expect(Validators.pattern("[a-zA-Z ]*")(new Control("aaa0")))
|
||||||
|
.toEqual({"pattern": {"requiredPattern": "^[a-zA-Z ]*$", "actualValue": "aaa0"}});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("compose", () => {
|
describe("compose", () => {
|
||||||
it("should return null when given null",
|
it("should return null when given null",
|
||||||
() => { expect(Validators.compose(null)).toBe(null); });
|
() => { expect(Validators.compose(null)).toBe(null); });
|
||||||
|
|
|
@ -427,6 +427,8 @@ var NG_COMMON = [
|
||||||
'ObservableListDiffFactory.create():dart',
|
'ObservableListDiffFactory.create():dart',
|
||||||
'ObservableListDiffFactory.supports():dart',
|
'ObservableListDiffFactory.supports():dart',
|
||||||
'ObservableListDiffFactory:dart',
|
'ObservableListDiffFactory:dart',
|
||||||
|
'PatternValidator',
|
||||||
|
'PatternValidator.validate()',
|
||||||
'PercentPipe',
|
'PercentPipe',
|
||||||
'PercentPipe.transform()',
|
'PercentPipe.transform()',
|
||||||
'RequiredValidator',
|
'RequiredValidator',
|
||||||
|
@ -452,6 +454,7 @@ var NG_COMMON = [
|
||||||
'Validators#maxLength()',
|
'Validators#maxLength()',
|
||||||
'Validators#minLength()',
|
'Validators#minLength()',
|
||||||
'Validators#nullValidator()',
|
'Validators#nullValidator()',
|
||||||
|
'Validators#pattern()',
|
||||||
'Validators#required()',
|
'Validators#required()',
|
||||||
'RadioButtonState',
|
'RadioButtonState',
|
||||||
'RadioButtonState.checked',
|
'RadioButtonState.checked',
|
||||||
|
|
|
@ -772,6 +772,9 @@ const COMMON = [
|
||||||
'NgSwitchWhen.constructor(viewContainer:ViewContainerRef, templateRef:TemplateRef, ngSwitch:NgSwitch)',
|
'NgSwitchWhen.constructor(viewContainer:ViewContainerRef, templateRef:TemplateRef, ngSwitch:NgSwitch)',
|
||||||
'NgSwitchWhen.ngSwitchWhen=(value:any)',
|
'NgSwitchWhen.ngSwitchWhen=(value:any)',
|
||||||
'NumberPipe',
|
'NumberPipe',
|
||||||
|
'PatternValidator',
|
||||||
|
'PatternValidator.constructor(pattern:string)',
|
||||||
|
'PatternValidator.validate(c:Control):{[key:string]:any}',
|
||||||
'PercentPipe',
|
'PercentPipe',
|
||||||
'PercentPipe.transform(value:any, args:any[]):string',
|
'PercentPipe.transform(value:any, args:any[]):string',
|
||||||
'RequiredValidator',
|
'RequiredValidator',
|
||||||
|
@ -795,6 +798,7 @@ const COMMON = [
|
||||||
'Validators.maxLength(maxLength:number):Function',
|
'Validators.maxLength(maxLength:number):Function',
|
||||||
'Validators.minLength(minLength:number):Function',
|
'Validators.minLength(minLength:number):Function',
|
||||||
'Validators.nullValidator(c:any):{[key:string]:boolean}',
|
'Validators.nullValidator(c:any):{[key:string]:boolean}',
|
||||||
|
'Validators.pattern(pattern:string):Function',
|
||||||
'Validators.required(control:Control):{[key:string]:boolean}',
|
'Validators.required(control:Control):{[key:string]:boolean}',
|
||||||
'RadioButtonState',
|
'RadioButtonState',
|
||||||
'RadioButtonState.constructor(checked:boolean, value:string)',
|
'RadioButtonState.constructor(checked:boolean, value:string)',
|
||||||
|
|
Loading…
Reference in New Issue