From c987988d7c970a43c09408a79378f2d37a913d65 Mon Sep 17 00:00:00 2001 From: Caitlin Potter Date: Tue, 29 Jul 2014 14:36:13 -0400 Subject: [PATCH] feat($compile): use allOrNothing interpolation for ngAttr* allOrNothing interpolation is now used for ng-attr-*, under all circumstances. This prevents uninitialized attributes from being added to the DOM with invalid values which cause errors to be shown. BREAKING CHANGE: Now, ng-attr-* will never add the attribute to the DOM if any of the interpolated expressions evaluate to `undefined`. To work around this, initialize values which are intended to be the empty string with the empty string: For example, given the following markup:
If $scope.value is `4`, and $scope.units is undefined, the resulting markup is unchanged:
However, if $scope.units is `""`, then the resulting markup is updated:
Closes #8376 --- src/ng/compile.js | 6 +++--- test/ng/compileSpec.js | 11 +++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/ng/compile.js b/src/ng/compile.js index a68fc2f091b9..942aef0539f5 100644 --- a/src/ng/compile.js +++ b/src/ng/compile.js @@ -1074,7 +1074,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { attrs[nName] = true; // presence means true } } - addAttrInterpolateDirective(node, directives, value, nName); + addAttrInterpolateDirective(node, directives, value, nName, isNgAttr); addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName, attrEndName); } @@ -1929,7 +1929,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { } - function addAttrInterpolateDirective(node, directives, value, name) { + function addAttrInterpolateDirective(node, directives, value, name, allOrNothing) { var interpolateFn = $interpolate(value, true); // no interpolation found -> ignore @@ -1958,7 +1958,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { // we need to interpolate again, in case the attribute value has been updated // (e.g. by another directive's compile function) interpolateFn = $interpolate(attr[name], true, getTrustedContext(node, name), - ALL_OR_NOTHING_ATTRS[name]); + ALL_OR_NOTHING_ATTRS[name] || allOrNothing); // if attribute was updated so that there is no interpolation going on we don't want to // register any observers diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js index 27661dfa0e45..17d458ad57fc 100755 --- a/test/ng/compileSpec.js +++ b/test/ng/compileSpec.js @@ -5423,6 +5423,17 @@ describe('$compile', function() { expect(element.attr('test')).toBe('Misko'); })); + it('should remove attribute if any bindings are undefined', inject(function($compile, $rootScope) { + element = $compile('')($rootScope); + $rootScope.$digest(); + expect(element.attr('test')).toBeUndefined(); + $rootScope.name = 'caitp'; + $rootScope.$digest(); + expect(element.attr('test')).toBeUndefined(); + $rootScope.emphasis = '!!!'; + $rootScope.$digest(); + expect(element.attr('test')).toBe('caitp!!!'); + })); describe('in directive', function() { beforeEach(module(function() {