From 9be1198aee58012b01f7915e16b241937a6c8e75 Mon Sep 17 00:00:00 2001 From: Martin Staffa Date: Wed, 20 Feb 2019 22:05:42 +0100 Subject: [PATCH 1/2] fix(required): correctly validate when required on non-input element is surrounded by ngIf Closes #16830 --- src/ng/directive/validators.js | 10 ++++++++-- test/ng/directive/validatorsSpec.js | 11 +++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/ng/directive/validators.js b/src/ng/directive/validators.js index 5c1649ecf74e..1c5872a15891 100644 --- a/src/ng/directive/validators.js +++ b/src/ng/directive/validators.js @@ -68,15 +68,21 @@ var requiredDirective = ['$parse', function($parse) { require: '?ngModel', link: function(scope, elm, attr, ctrl) { if (!ctrl) return; - var value = attr.required || $parse(attr.ngRequired)(scope); + // For boolean attributes like required, presence means true + var value = 'required' in attr || $parse(attr.ngRequired)(scope); - attr.required = true; // force truthy in case we are on non input element + if (!attr.ngRequired) { + // force truthy in case we are on non input element + // (input elements do this automatically for boolean attributes like required) + attr.required = true; + } ctrl.$validators.required = function(modelValue, viewValue) { return !value || !ctrl.$isEmpty(viewValue); }; attr.$observe('required', function(newVal) { + if (value !== newVal) { value = newVal; ctrl.$validate(); diff --git a/test/ng/directive/validatorsSpec.js b/test/ng/directive/validatorsSpec.js index a851b2fec95c..ffd5d5aced0f 100644 --- a/test/ng/directive/validatorsSpec.js +++ b/test/ng/directive/validatorsSpec.js @@ -731,6 +731,7 @@ describe('validators', function() { expect(helper.validationCounter.required).toBe(1); }); + it('should validate once when inside ngRepeat, and set the "required" error when ngRequired is false by default', function() { $rootScope.isRequired = false; $rootScope.refs = {}; @@ -744,5 +745,15 @@ describe('validators', function() { expect($rootScope.refs.input.$error.required).toBeUndefined(); }); + + it('should validate only once when inside ngIf with required on non-input elements', inject(function($compile) { + $rootScope.value = '12'; + $rootScope.refs = {}; + helper.compileInput('
'); + $rootScope.$digest(); + + expect(helper.validationCounter.required).toBe(1); + expect($rootScope.refs.ctrl.$error.required).not.toBe(true); + })); }); }); From 2cdae38de26a481e5b75e9841adc2b681b6e7857 Mon Sep 17 00:00:00 2001 From: Martin Staffa Date: Mon, 25 Feb 2019 09:34:05 +0100 Subject: [PATCH 2/2] fixup! fix(required): correctly validate when required on non-input element is surrounded by ngIf --- src/ng/directive/validators.js | 2 +- test/ng/directive/validatorsSpec.js | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ng/directive/validators.js b/src/ng/directive/validators.js index 1c5872a15891..787a80a71ab7 100644 --- a/src/ng/directive/validators.js +++ b/src/ng/directive/validators.js @@ -69,7 +69,7 @@ var requiredDirective = ['$parse', function($parse) { link: function(scope, elm, attr, ctrl) { if (!ctrl) return; // For boolean attributes like required, presence means true - var value = 'required' in attr || $parse(attr.ngRequired)(scope); + var value = attr.hasOwnProperty('required') || $parse(attr.ngRequired)(scope); if (!attr.ngRequired) { // force truthy in case we are on non input element diff --git a/test/ng/directive/validatorsSpec.js b/test/ng/directive/validatorsSpec.js index ffd5d5aced0f..c7259c67c933 100644 --- a/test/ng/directive/validatorsSpec.js +++ b/test/ng/directive/validatorsSpec.js @@ -696,6 +696,13 @@ describe('validators', function() { })); + it('should override "required" when ng-required="false" is set', function() { + var inputElm = helper.compileInput(''); + + expect(inputElm).toBeValid(); + }); + + it('should validate only once after compilation when inside ngRepeat', function() { helper.compileInput( '
' +