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

Commit

Permalink
feat($compile): use allOrNothing interpolation for ngAttr*
Browse files Browse the repository at this point in the history
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:

    <div ng-attr-style="border-radius: {{value}}{{units}}"></div>

If $scope.value is `4`, and $scope.units is undefined, the resulting markup is unchanged:

    <div ng-attr-style="border-radius: {{value}}{{units}}"></div>

However, if $scope.units is `""`, then the resulting markup is updated:

    <div ng-attr-style="border-radius: {{value}}{{units}}" style="border-radius: 4"></div>

Closes #8376
Closes #8399
  • Loading branch information
caitp committed Aug 21, 2014
1 parent a7fb357 commit 09de7b5
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 4 deletions.
4 changes: 3 additions & 1 deletion docs/content/guide/directive.ngdoc
Expand Up @@ -161,7 +161,9 @@ With `ng-attr-cx` you can work around this problem.
If an attribute with a binding is prefixed with the `ngAttr` prefix (denormalized as `ng-attr-`)
then during the binding will be applied to the corresponding unprefixed attribute. This allows
you to bind to attributes that would otherwise be eagerly processed by browsers
(e.g. an SVG element's `circle[cx]` attributes).
(e.g. an SVG element's `circle[cx]` attributes). When using `ngAttr`, the `allOrNothing` flag of
{@link ng.$interpolate $interpolate} is used, so if any expression in the interpolated string
results in `undefined`, the attribute is removed and not added to the element.

For example, we could fix the example above by instead writing:

Expand Down
6 changes: 3 additions & 3 deletions src/ng/compile.js
Expand Up @@ -1104,7 +1104,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);
}
Expand Down Expand Up @@ -1984,7 +1984,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
Expand Down Expand Up @@ -2013,7 +2013,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
Expand Down
11 changes: 11 additions & 0 deletions test/ng/compileSpec.js
Expand Up @@ -5579,6 +5579,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('<span ng-attr-test="{{name}}{{emphasis}}"></span>')($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() {
Expand Down

0 comments on commit 09de7b5

Please sign in to comment.