Skip to content

Commit 4e27938

Browse files
lrlopezIgorMinar
authored andcommitted
feat($compile): Allow late binding attributes
Sometimes is not desirable to use interpolation on attributes because the user agent parses them before the interpolation takes place. I.e: <svg> <circle cx="{{cx}}" cy="{{cy}}" r="{{r}}"></circle> </svg> The snippet throws three browser errors, one for each attribute. For some attributes, AngularJS fixes that behaviour introducing special directives like ng-href or ng-src. This commit is a more general solution that allows prefixing any attribute with "ng-attr-", "ng:attr:" or "ng_attr_" so it will be set only when the binding is done. The prefix is then removed. I.e: <svg> <circle ng_attr_cx="{{cx}}" ng-attr-cy="{{cy}}" ng:Attr:r="{{r}}"></circle> </svg> Closes angular#1050 Closes angular#1925
1 parent 86d191e commit 4e27938

File tree

3 files changed

+45
-1
lines changed

3 files changed

+45
-1
lines changed

docs/content/guide/directive.ngdoc

+3
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,9 @@ link() or compile() functions - is a way of accessing:
488488
such as 'ng:bind', or 'x-ng-bind', the attributes object allows for normalized accessed to
489489
the attributes.
490490

491+
* *late binding attributes: If the attribute is prefixed with 'ng-attr-', 'ng:attr:' or 'ng_attr_'
492+
the prefix will be removed once the attribute is evaluated, allowing late binding.
493+
491494
* *directive inter-communication:* All directives share the same instance of the attributes
492495
object which allows the directives to use the attributes object as inter directive
493496
communication.

src/ng/compile.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -514,11 +514,16 @@ function $CompileProvider($provide) {
514514
directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority);
515515

516516
// iterate over the attributes
517-
for (var attr, name, nName, value, nAttrs = node.attributes,
517+
for (var attr, name, nName, lName, value, nAttrs = node.attributes,
518518
j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
519519
attr = nAttrs[j];
520520
if (attr.specified) {
521521
name = attr.name;
522+
// support late binding attributes
523+
lName = directiveNormalize(name);
524+
if (/ngAttr[A-Z]/.test(lName)) {
525+
name = lName.substr(6).toLowerCase();
526+
}
522527
nName = directiveNormalize(name.toLowerCase());
523528
attrsMap[nName] = name;
524529
attrs[nName] = value = trim((msie && name == 'href')

test/ng/compileSpec.js

+36
Original file line numberDiff line numberDiff line change
@@ -2591,4 +2591,40 @@ describe('$compile', function() {
25912591
});
25922592
});
25932593
});
2594+
2595+
describe('late binding attributes', function() {
2596+
2597+
it('should bind after digest but not before', inject(function($compile, $rootScope) {
2598+
$rootScope.name = "Misko";
2599+
element = $compile('<span ng-attr-test="{{name}}"></span>')($rootScope);
2600+
expect(element.attr('test')).toBeUndefined();
2601+
$rootScope.$digest();
2602+
expect(element.attr('test')).toBe('Misko');
2603+
}));
2604+
2605+
it('should work with different prefixes', inject(function($compile, $rootScope) {
2606+
$rootScope.name = "Misko";
2607+
element = $compile('<span ng:attr:test="{{name}}" ng-Attr-test2="{{name}}" ng_Attr_test3="{{name}}"></span>')($rootScope);
2608+
expect(element.attr('test')).toBeUndefined();
2609+
expect(element.attr('test2')).toBeUndefined();
2610+
expect(element.attr('test2')).toBeUndefined();
2611+
$rootScope.$digest();
2612+
expect(element.attr('test')).toBe('Misko');
2613+
expect(element.attr('test2')).toBe('Misko');
2614+
expect(element.attr('test3')).toBe('Misko');
2615+
}));
2616+
2617+
it('should work if they are prefixed with x- or data-', inject(function($compile, $rootScope) {
2618+
$rootScope.name = "Misko";
2619+
element = $compile('<span data-ng-attr-test2="{{name}}" x-ng-attr-test3="{{name}}" data-ng:attr-test4="{{name}}"></span>')($rootScope);
2620+
expect(element.attr('test2')).toBeUndefined();
2621+
expect(element.attr('test3')).toBeUndefined();
2622+
expect(element.attr('test4')).toBeUndefined();
2623+
$rootScope.$digest();
2624+
expect(element.attr('test2')).toBe('Misko');
2625+
expect(element.attr('test3')).toBe('Misko');
2626+
expect(element.attr('test4')).toBe('Misko');
2627+
}));
2628+
});
2629+
25942630
});

0 commit comments

Comments
 (0)