Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 85eb966

Browse files
caitppetebacondarwin
authored andcommitted
fix(ngPattern): match behaviour of native HTML pattern attribute
From https://html.spec.whatwg.org/multipage/forms.html#attr-input-pattern > The compiled pattern regular expression, when matched against a string, must have its start anchored to the start of the string and its end anchored to the end of the string. Closes #9881 Closes #9888
1 parent d81ff88 commit 85eb966

File tree

2 files changed

+80
-13
lines changed

2 files changed

+80
-13
lines changed

src/ng/directive/input.js

+33-13
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,14 @@ var inputType = {
4242
* minlength.
4343
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
4444
* maxlength.
45-
* @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
46-
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
47-
* patterns defined as scope expressions.
45+
* @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
46+
* that contains the regular expression body that will be converted to a regular expression
47+
* as in the ngPattern directive.
48+
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
49+
* a RegExp found by evaluating the Angular expression given in the attribute value.
50+
* If the expression evaluates to a RegExp object then this is used directly.
51+
* If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
52+
* characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
4853
* @param {string=} ngChange Angular expression to be executed when input changes due to user
4954
* interaction with the input element.
5055
* @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
@@ -585,9 +590,14 @@ var inputType = {
585590
* minlength.
586591
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
587592
* maxlength.
588-
* @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
589-
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
590-
* patterns defined as scope expressions.
593+
* @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
594+
* that contains the regular expression body that will be converted to a regular expression
595+
* as in the ngPattern directive.
596+
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
597+
* a RegExp found by evaluating the Angular expression given in the attribute value.
598+
* If the expression evaluates to a RegExp object then this is used directly.
599+
* If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
600+
* characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
591601
* @param {string=} ngChange Angular expression to be executed when input changes due to user
592602
* interaction with the input element.
593603
*
@@ -667,9 +677,14 @@ var inputType = {
667677
* minlength.
668678
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
669679
* maxlength.
670-
* @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
671-
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
672-
* patterns defined as scope expressions.
680+
* @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
681+
* that contains the regular expression body that will be converted to a regular expression
682+
* as in the ngPattern directive.
683+
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
684+
* a RegExp found by evaluating the Angular expression given in the attribute value.
685+
* If the expression evaluates to a RegExp object then this is used directly.
686+
* If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
687+
* characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
673688
* @param {string=} ngChange Angular expression to be executed when input changes due to user
674689
* interaction with the input element.
675690
*
@@ -750,9 +765,14 @@ var inputType = {
750765
* minlength.
751766
* @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
752767
* maxlength.
753-
* @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
754-
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
755-
* patterns defined as scope expressions.
768+
* @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
769+
* that contains the regular expression body that will be converted to a regular expression
770+
* as in the ngPattern directive.
771+
* @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
772+
* a RegExp found by evaluating the Angular expression given in the attribute value.
773+
* If the expression evaluates to a RegExp object then this is used directly.
774+
* If the expression is a string then it will be converted to a RegExp after wrapping it in `^` and `$`
775+
* characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
756776
* @param {string=} ngChange Angular expression to be executed when input changes due to user
757777
* interaction with the input element.
758778
*
@@ -2582,7 +2602,7 @@ var patternDirective = function() {
25822602
var regexp, patternExp = attr.ngPattern || attr.pattern;
25832603
attr.$observe('pattern', function(regex) {
25842604
if (isString(regex) && regex.length > 0) {
2585-
regex = new RegExp(regex);
2605+
regex = new RegExp('^' + regex + '$');
25862606
}
25872607

25882608
if (regex && !regex.test) {

test/ng/directive/inputSpec.js

+47
Original file line numberDiff line numberDiff line change
@@ -2224,6 +2224,53 @@ describe('input', function() {
22242224
});
22252225
}).toThrowMatching(/^\[ngPattern:noregexp\] Expected fooRegexp to be a RegExp but was/);
22262226
});
2227+
2228+
it('should be invalid if entire string does not match pattern', function() {
2229+
compileInput('<input type="text" name="test" ng-model="value" pattern="\\d{4}">');
2230+
changeInputValueTo('1234');
2231+
expect(scope.form.test.$error.pattern).not.toBe(true);
2232+
expect(inputElm).toBeValid();
2233+
2234+
changeInputValueTo('123');
2235+
expect(scope.form.test.$error.pattern).toBe(true);
2236+
expect(inputElm).not.toBeValid();
2237+
2238+
changeInputValueTo('12345');
2239+
expect(scope.form.test.$error.pattern).toBe(true);
2240+
expect(inputElm).not.toBeValid();
2241+
});
2242+
2243+
2244+
it('should be cope with patterns that start with ^', function() {
2245+
compileInput('<input type="text" name="test" ng-model="value" pattern="^\\d{4}">');
2246+
changeInputValueTo('1234');
2247+
expect(scope.form.test.$error.pattern).not.toBe(true);
2248+
expect(inputElm).toBeValid();
2249+
2250+
changeInputValueTo('123');
2251+
expect(scope.form.test.$error.pattern).toBe(true);
2252+
expect(inputElm).not.toBeValid();
2253+
2254+
changeInputValueTo('12345');
2255+
expect(scope.form.test.$error.pattern).toBe(true);
2256+
expect(inputElm).not.toBeValid();
2257+
});
2258+
2259+
2260+
it('should be cope with patterns that end with $', function() {
2261+
compileInput('<input type="text" name="test" ng-model="value" pattern="\\d{4}$">');
2262+
changeInputValueTo('1234');
2263+
expect(scope.form.test.$error.pattern).not.toBe(true);
2264+
expect(inputElm).toBeValid();
2265+
2266+
changeInputValueTo('123');
2267+
expect(scope.form.test.$error.pattern).toBe(true);
2268+
expect(inputElm).not.toBeValid();
2269+
2270+
changeInputValueTo('12345');
2271+
expect(scope.form.test.$error.pattern).toBe(true);
2272+
expect(inputElm).not.toBeValid();
2273+
});
22272274
});
22282275

22292276

0 commit comments

Comments
 (0)