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

feat($compile): Allow late binding attributes #2061

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/content/guide/directive.ngdoc
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,9 @@ link() or compile() functions - is a way of accessing:
such as 'ng:bind', or 'x-ng-bind', the attributes object allows for normalized accessed to
the attributes.

* *late binding attributes: If the attribute is prefixed with 'ng-attr-', 'ng:attr:' or 'ng_attr_'
the prefix will be removed once the attribute is evaluated, allowing late binding.

* *directive inter-communication:* All directives share the same instance of the attributes
object which allows the directives to use the attributes object as inter directive
communication.
Expand Down
7 changes: 6 additions & 1 deletion src/ng/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -514,11 +514,16 @@ function $CompileProvider($provide) {
directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority);

// iterate over the attributes
for (var attr, name, nName, value, nAttrs = node.attributes,
for (var attr, name, nName, lName, value, nAttrs = node.attributes,
j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
attr = nAttrs[j];
if (attr.specified) {
name = attr.name;
// support late binding attributes
lName = directiveNormalize(name);
if (/ngAttr[A-Z]/.test(lName)) {
name = lName.substr(6).toLowerCase();
}
nName = directiveNormalize(name.toLowerCase());
attrsMap[nName] = name;
attrs[nName] = value = trim((msie && name == 'href')
Expand Down
36 changes: 36 additions & 0 deletions test/ng/compileSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2498,4 +2498,40 @@ describe('$compile', function() {
});
});
});

describe('late binding attributes', function() {

it('should bind after digest but not before', inject(function($compile, $rootScope) {
$rootScope.name = "Misko";
element = $compile('<span ng-attr-test="{{name}}"></span>')($rootScope);
expect(element.attr('test')).toBeUndefined();
$rootScope.$digest();
expect(element.attr('test')).toBe('Misko');
}));

it('should work with different prefixes', inject(function($compile, $rootScope) {
$rootScope.name = "Misko";
element = $compile('<span ng:attr:test="{{name}}" ng-Attr-test2="{{name}}" ng_Attr_test3="{{name}}"></span>')($rootScope);
expect(element.attr('test')).toBeUndefined();
expect(element.attr('test2')).toBeUndefined();
expect(element.attr('test2')).toBeUndefined();
$rootScope.$digest();
expect(element.attr('test')).toBe('Misko');
expect(element.attr('test2')).toBe('Misko');
expect(element.attr('test3')).toBe('Misko');
}));

it('should work if they are prefixed with x- or data-', inject(function($compile, $rootScope) {
$rootScope.name = "Misko";
element = $compile('<span data-ng-attr-test2="{{name}}" x-ng-attr-test3="{{name}}" data-ng:attr-test4="{{name}}"></span>')($rootScope);
expect(element.attr('test2')).toBeUndefined();
expect(element.attr('test3')).toBeUndefined();
expect(element.attr('test4')).toBeUndefined();
$rootScope.$digest();
expect(element.attr('test2')).toBe('Misko');
expect(element.attr('test3')).toBe('Misko');
expect(element.attr('test4')).toBe('Misko');
}));
});

});