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

Commit b04fc58

Browse files
committed
fix(ngModel): let aliased validator directives work on any element
`ng(Pattern|Minlength|Maxlength)` directives will now validate the `ngModel` when on an element that is not an `input` or a `textarea`. Previously, only their HTML5 counterparts worked on every element. This is because the three validators were extracted into separate directives (see 26d91b6 and 1be9bb9), whereas the aliased attribute handling assumes the validators will only exist on `input|textarea` (see d9b90d7 and 25541c1). Since `ngMin` and `ngMax` are also aliased attributes, this means observers of `min` and `max` will be fired if `ngMin` and `ngMax` change. This will happen on any element, even if it does not have an `ngModel`. However, since min/max validators are only ever added as part of the `input[number|textarea]` types, even if the element has an `ngModel`, no validators will be added. Finally the commit also tests that `ng-required` works on any element, although that validator worked on all elements before this fix. Fixes #12158 Closes #12658
1 parent 0e00108 commit b04fc58

File tree

3 files changed

+76
-4
lines changed

3 files changed

+76
-4
lines changed

src/jqLite.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -556,9 +556,8 @@ function getBooleanAttrName(element, name) {
556556
return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
557557
}
558558

559-
function getAliasedAttrName(element, name) {
560-
var nodeName = element.nodeName;
561-
return (nodeName === 'INPUT' || nodeName === 'TEXTAREA') && ALIASED_ATTR[name];
559+
function getAliasedAttrName(name) {
560+
return ALIASED_ATTR[name];
562561
}
563562

564563
forEach({

src/ng/compile.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1077,7 +1077,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
10771077

10781078
var node = this.$$element[0],
10791079
booleanKey = getBooleanAttrName(node, key),
1080-
aliasedKey = getAliasedAttrName(node, key),
1080+
aliasedKey = getAliasedAttrName(key),
10811081
observer = key,
10821082
nodeName;
10831083

test/ng/directive/validatorsSpec.js

+73
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,24 @@ describe('validators', function() {
219219
expect($rootScope.form.test.$modelValue).toBe('12340');
220220
expect(inputElm).toBeValid();
221221
});
222+
223+
224+
it('should validate on non-input elements', inject(function($compile) {
225+
$rootScope.pattern = '\\d{4}';
226+
var elm = $compile('<span ng-model="value" pattern="\\d{4}"></span>')($rootScope);
227+
var elmNg = $compile('<span ng-model="value" ng-pattern="pattern"></span>')($rootScope);
228+
var ctrl = elm.controller('ngModel');
229+
var ctrlNg = elmNg.controller('ngModel');
230+
231+
expect(ctrl.$error.pattern).not.toBe(true);
232+
expect(ctrlNg.$error.pattern).not.toBe(true);
233+
234+
ctrl.$setViewValue('12');
235+
ctrlNg.$setViewValue('12');
236+
237+
expect(ctrl.$error.pattern).toBe(true);
238+
expect(ctrlNg.$error.pattern).toBe(true);
239+
}));
222240
});
223241

224242

@@ -283,6 +301,24 @@ describe('validators', function() {
283301
helper.changeInputValueTo('12345');
284302
expect(ctrl.$isEmpty).toHaveBeenCalledWith('12345');
285303
});
304+
305+
306+
it('should validate on non-input elements', inject(function($compile) {
307+
$rootScope.min = 3;
308+
var elm = $compile('<span ng-model="value" minlength="{{min}}"></span>')($rootScope);
309+
var elmNg = $compile('<span ng-model="value" ng-minlength="min"></span>')($rootScope);
310+
var ctrl = elm.controller('ngModel');
311+
var ctrlNg = elmNg.controller('ngModel');
312+
313+
expect(ctrl.$error.minlength).not.toBe(true);
314+
expect(ctrlNg.$error.minlength).not.toBe(true);
315+
316+
ctrl.$setViewValue('12');
317+
ctrlNg.$setViewValue('12');
318+
319+
expect(ctrl.$error.minlength).toBe(true);
320+
expect(ctrlNg.$error.minlength).toBe(true);
321+
}));
286322
});
287323

288324

@@ -453,6 +489,24 @@ describe('validators', function() {
453489
helper.changeInputValueTo('12345');
454490
expect(ctrl.$isEmpty).toHaveBeenCalledWith('12345');
455491
});
492+
493+
494+
it('should validate on non-input elements', inject(function($compile) {
495+
$rootScope.max = 3;
496+
var elm = $compile('<span ng-model="value" maxlength="{{max}}"></span>')($rootScope);
497+
var elmNg = $compile('<span ng-model="value" ng-maxlength="max"></span>')($rootScope);
498+
var ctrl = elm.controller('ngModel');
499+
var ctrlNg = elmNg.controller('ngModel');
500+
501+
expect(ctrl.$error.maxlength).not.toBe(true);
502+
expect(ctrlNg.$error.maxlength).not.toBe(true);
503+
504+
ctrl.$setViewValue('1234');
505+
ctrlNg.$setViewValue('1234');
506+
507+
expect(ctrl.$error.maxlength).toBe(true);
508+
expect(ctrlNg.$error.maxlength).toBe(true);
509+
}));
456510
});
457511

458512

@@ -547,6 +601,7 @@ describe('validators', function() {
547601
expect(inputElm).toBeValid();
548602
});
549603

604+
550605
it('should validate emptiness against the viewValue', function() {
551606
var inputElm = helper.compileInput('<input type="text" name="input" ng-model="value" required />');
552607

@@ -560,5 +615,23 @@ describe('validators', function() {
560615
helper.changeInputValueTo('12345');
561616
expect(ctrl.$isEmpty).toHaveBeenCalledWith('12345');
562617
});
618+
619+
620+
it('should validate on non-input elements', inject(function($compile) {
621+
$rootScope.value = '12';
622+
var elm = $compile('<span ng-model="value" required></span>')($rootScope);
623+
var elmNg = $compile('<span ng-model="value" ng-required="true"></span>')($rootScope);
624+
var ctrl = elm.controller('ngModel');
625+
var ctrlNg = elmNg.controller('ngModel');
626+
627+
expect(ctrl.$error.required).not.toBe(true);
628+
expect(ctrlNg.$error.required).not.toBe(true);
629+
630+
ctrl.$setViewValue('');
631+
ctrlNg.$setViewValue('');
632+
633+
expect(ctrl.$error.required).toBe(true);
634+
expect(ctrlNg.$error.required).toBe(true);
635+
}));
563636
});
564637
});

0 commit comments

Comments
 (0)