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

Commit b063d30

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 aforementioned validators were extracted into separate directives, whereas the aliased attribute handling assumes the validators will only exist on `input|textarea` The commit also adds a test for `ng-required`, although that validator worked on all elements before this fix. Fixes #12158
1 parent 0e00108 commit b063d30

File tree

3 files changed

+76
-4
lines changed

3 files changed

+76
-4
lines changed

src/jqLite.js

Lines changed: 2 additions & 3 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 73 additions & 0 deletions
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)