feat(forms): Validator.pattern accepts a RegExp (#12323)
This commit is contained in:
parent
cca4a5c519
commit
bf60418fdc
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
import {OpaqueToken} from '@angular/core';
|
import {OpaqueToken} from '@angular/core';
|
||||||
import {toPromise} from 'rxjs/operator/toPromise';
|
import {toPromise} from 'rxjs/operator/toPromise';
|
||||||
|
|
||||||
import {AsyncValidatorFn, ValidatorFn} from './directives/validators';
|
import {AsyncValidatorFn, ValidatorFn} from './directives/validators';
|
||||||
import {StringMapWrapper} from './facade/collection';
|
import {StringMapWrapper} from './facade/collection';
|
||||||
import {isPresent} from './facade/lang';
|
import {isPresent} from './facade/lang';
|
||||||
|
@ -95,16 +94,24 @@ export class Validators {
|
||||||
/**
|
/**
|
||||||
* Validator that requires a control to match a regex to its value.
|
* Validator that requires a control to match a regex to its value.
|
||||||
*/
|
*/
|
||||||
static pattern(pattern: string): ValidatorFn {
|
static pattern(pattern: string|RegExp): ValidatorFn {
|
||||||
|
if (!pattern) return Validators.nullValidator;
|
||||||
|
let regex: RegExp;
|
||||||
|
let regexStr: string;
|
||||||
|
if (typeof pattern === 'string') {
|
||||||
|
regexStr = `^${pattern}$`;
|
||||||
|
regex = new RegExp(regexStr);
|
||||||
|
} else {
|
||||||
|
regexStr = pattern.toString();
|
||||||
|
regex = pattern;
|
||||||
|
}
|
||||||
return (control: AbstractControl): {[key: string]: any} => {
|
return (control: AbstractControl): {[key: string]: any} => {
|
||||||
if (isEmptyInputValue(control.value)) {
|
if (isEmptyInputValue(control.value)) {
|
||||||
return null; // don't validate empty values to allow optional controls
|
return null; // don't validate empty values to allow optional controls
|
||||||
}
|
}
|
||||||
const regex = new RegExp(`^${pattern}$`);
|
|
||||||
const value: string = control.value;
|
const value: string = control.value;
|
||||||
return regex.test(value) ?
|
return regex.test(value) ? null :
|
||||||
null :
|
{'pattern': {'requiredPattern': regexStr, 'actualValue': value}};
|
||||||
{'pattern': {'requiredPattern': `^${pattern}$`, 'actualValue': value}};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +126,7 @@ export class Validators {
|
||||||
*/
|
*/
|
||||||
static compose(validators: ValidatorFn[]): ValidatorFn {
|
static compose(validators: ValidatorFn[]): ValidatorFn {
|
||||||
if (!validators) return null;
|
if (!validators) return null;
|
||||||
var presentValidators = validators.filter(isPresent);
|
const presentValidators = validators.filter(isPresent);
|
||||||
if (presentValidators.length == 0) return null;
|
if (presentValidators.length == 0) return null;
|
||||||
|
|
||||||
return function(control: AbstractControl) {
|
return function(control: AbstractControl) {
|
||||||
|
@ -129,7 +136,7 @@ export class Validators {
|
||||||
|
|
||||||
static composeAsync(validators: AsyncValidatorFn[]): AsyncValidatorFn {
|
static composeAsync(validators: AsyncValidatorFn[]): AsyncValidatorFn {
|
||||||
if (!validators) return null;
|
if (!validators) return null;
|
||||||
var presentValidators = validators.filter(isPresent);
|
const presentValidators = validators.filter(isPresent);
|
||||||
if (presentValidators.length == 0) return null;
|
if (presentValidators.length == 0) return null;
|
||||||
|
|
||||||
return function(control: AbstractControl) {
|
return function(control: AbstractControl) {
|
||||||
|
@ -152,7 +159,7 @@ function _executeAsyncValidators(control: AbstractControl, validators: AsyncVali
|
||||||
}
|
}
|
||||||
|
|
||||||
function _mergeErrors(arrayOfErrors: any[]): {[key: string]: any} {
|
function _mergeErrors(arrayOfErrors: any[]): {[key: string]: any} {
|
||||||
var res: {[key: string]: any} =
|
const res: {[key: string]: any} =
|
||||||
arrayOfErrors.reduce((res: {[key: string]: any}, errors: {[key: string]: any}) => {
|
arrayOfErrors.reduce((res: {[key: string]: any}, errors: {[key: string]: any}) => {
|
||||||
return isPresent(errors) ? StringMapWrapper.merge(res, errors) : res;
|
return isPresent(errors) ? StringMapWrapper.merge(res, errors) : res;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
|
@ -17,7 +17,7 @@ import {EventEmitter} from '../src/facade/async';
|
||||||
export function main() {
|
export function main() {
|
||||||
function validator(key: string, error: any) {
|
function validator(key: string, error: any) {
|
||||||
return function(c: AbstractControl) {
|
return function(c: AbstractControl) {
|
||||||
var r: {[k: string]: string} = {};
|
const r: {[k: string]: string} = {};
|
||||||
r[key] = error;
|
r[key] = error;
|
||||||
return r;
|
return r;
|
||||||
};
|
};
|
||||||
|
@ -101,13 +101,31 @@ export function main() {
|
||||||
() => { expect(Validators.pattern('null')(new FormControl(null))).toBeNull(); });
|
() => { expect(Validators.pattern('null')(new FormControl(null))).toBeNull(); });
|
||||||
|
|
||||||
it('should not error on valid strings',
|
it('should not error on valid strings',
|
||||||
() => { expect(Validators.pattern('[a-zA-Z ]*')(new FormControl('aaAA'))).toBeNull(); });
|
() => expect(Validators.pattern('[a-zA-Z ]*')(new FormControl('aaAA'))).toBeNull());
|
||||||
|
|
||||||
it('should error on failure to match string', () => {
|
it('should error on failure to match string', () => {
|
||||||
expect(Validators.pattern('[a-zA-Z ]*')(new FormControl('aaa0'))).toEqual({
|
expect(Validators.pattern('[a-zA-Z ]*')(new FormControl('aaa0'))).toEqual({
|
||||||
'pattern': {'requiredPattern': '^[a-zA-Z ]*$', 'actualValue': 'aaa0'}
|
'pattern': {'requiredPattern': '^[a-zA-Z ]*$', 'actualValue': 'aaa0'}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should accept RegExp object', () => {
|
||||||
|
const pattern: RegExp = new RegExp('[a-zA-Z ]+');
|
||||||
|
expect(Validators.pattern(pattern)(new FormControl('aaAA'))).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should error on failure to match RegExp object', () => {
|
||||||
|
const pattern: RegExp = new RegExp('^[a-zA-Z ]*$');
|
||||||
|
expect(Validators.pattern(pattern)(new FormControl('aaa0'))).toEqual({
|
||||||
|
'pattern': {'requiredPattern': '/^[a-zA-Z ]*$/', 'actualValue': 'aaa0'}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not error on "null" pattern',
|
||||||
|
() => expect(Validators.pattern(null)(new FormControl('aaAA'))).toBeNull());
|
||||||
|
|
||||||
|
it('should not error on "undefined" pattern',
|
||||||
|
() => expect(Validators.pattern(undefined)(new FormControl('aaAA'))).toBeNull());
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('compose', () => {
|
describe('compose', () => {
|
||||||
|
@ -115,22 +133,22 @@ export function main() {
|
||||||
() => { expect(Validators.compose(null)).toBe(null); });
|
() => { expect(Validators.compose(null)).toBe(null); });
|
||||||
|
|
||||||
it('should collect errors from all the validators', () => {
|
it('should collect errors from all the validators', () => {
|
||||||
var c = Validators.compose([validator('a', true), validator('b', true)]);
|
const c = Validators.compose([validator('a', true), validator('b', true)]);
|
||||||
expect(c(new FormControl(''))).toEqual({'a': true, 'b': true});
|
expect(c(new FormControl(''))).toEqual({'a': true, 'b': true});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should run validators left to right', () => {
|
it('should run validators left to right', () => {
|
||||||
var c = Validators.compose([validator('a', 1), validator('a', 2)]);
|
const c = Validators.compose([validator('a', 1), validator('a', 2)]);
|
||||||
expect(c(new FormControl(''))).toEqual({'a': 2});
|
expect(c(new FormControl(''))).toEqual({'a': 2});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return null when no errors', () => {
|
it('should return null when no errors', () => {
|
||||||
var c = Validators.compose([Validators.nullValidator, Validators.nullValidator]);
|
const c = Validators.compose([Validators.nullValidator, Validators.nullValidator]);
|
||||||
expect(c(new FormControl(''))).toBeNull();
|
expect(c(new FormControl(''))).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should ignore nulls', () => {
|
it('should ignore nulls', () => {
|
||||||
var c = Validators.compose([null, Validators.required]);
|
const c = Validators.compose([null, Validators.required]);
|
||||||
expect(c(new FormControl(''))).toEqual({'required': true});
|
expect(c(new FormControl(''))).toEqual({'required': true});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -517,7 +517,7 @@ export declare class Validators {
|
||||||
static nullValidator(c: AbstractControl): {
|
static nullValidator(c: AbstractControl): {
|
||||||
[key: string]: boolean;
|
[key: string]: boolean;
|
||||||
};
|
};
|
||||||
static pattern(pattern: string): ValidatorFn;
|
static pattern(pattern: string | RegExp): ValidatorFn;
|
||||||
static required(control: AbstractControl): {
|
static required(control: AbstractControl): {
|
||||||
[key: string]: boolean;
|
[key: string]: boolean;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue