fix($compile): bind ng-attr-* even if unbound attribute follows ng-attr-*
Previously, <element ng-attr-foo="{{binding}}" foo="bar"></element>'s "foo" attribute would always
equal "bar", because the bound version was overwritten. This CL corrects this behaviour and ensures
that the ordering of attributes does not have an effect on whether or not ng-attr-bound attributes
do their work.
This commit is contained in:
committed by
Caitlin Potter
parent
d8e5acfe27
commit
ed59370d80
+9
-5
@@ -1010,7 +1010,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority, ignoreDirective);
|
||||
|
||||
// iterate over the attributes
|
||||
for (var attr, name, nName, ngAttrName, value, nAttrs = node.attributes,
|
||||
for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
|
||||
j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
|
||||
var attrStartName = false;
|
||||
var attrEndName = false;
|
||||
@@ -1018,9 +1018,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
attr = nAttrs[j];
|
||||
if (!msie || msie >= 8 || attr.specified) {
|
||||
name = attr.name;
|
||||
value = trim(attr.value);
|
||||
|
||||
// support ngAttr attribute binding
|
||||
ngAttrName = directiveNormalize(name);
|
||||
if (NG_ATTR_BINDING.test(ngAttrName)) {
|
||||
if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
|
||||
name = snake_case(ngAttrName.substr(6), '-');
|
||||
}
|
||||
|
||||
@@ -1033,9 +1035,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
|
||||
|
||||
nName = directiveNormalize(name.toLowerCase());
|
||||
attrsMap[nName] = name;
|
||||
attrs[nName] = value = trim(attr.value);
|
||||
if (getBooleanAttrName(node, nName)) {
|
||||
attrs[nName] = true; // presence means true
|
||||
if (isNgAttr || !attrs.hasOwnProperty(nName)) {
|
||||
attrs[nName] = value;
|
||||
if (getBooleanAttrName(node, nName)) {
|
||||
attrs[nName] = true; // presence means true
|
||||
}
|
||||
}
|
||||
addAttrInterpolateDirective(node, directives, value, nName);
|
||||
addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
|
||||
|
||||
@@ -4901,6 +4901,83 @@ describe('$compile', function() {
|
||||
expect(element.attr('test')).toBe('Misko');
|
||||
}));
|
||||
|
||||
it('should bind after digest but not before when after overridden attribute', inject(function($compile, $rootScope) {
|
||||
$rootScope.name = "Misko";
|
||||
element = $compile('<span test="123" ng-attr-test="{{name}}"></span>')($rootScope);
|
||||
expect(element.attr('test')).toBe('123');
|
||||
$rootScope.$digest();
|
||||
expect(element.attr('test')).toBe('Misko');
|
||||
}));
|
||||
|
||||
it('should bind after digest but not before when before overridden attribute', inject(function($compile, $rootScope) {
|
||||
$rootScope.name = "Misko";
|
||||
element = $compile('<span ng-attr-test="{{name}}" test="123"></span>')($rootScope);
|
||||
expect(element.attr('test')).toBe('123');
|
||||
$rootScope.$digest();
|
||||
expect(element.attr('test')).toBe('Misko');
|
||||
}));
|
||||
|
||||
|
||||
describe('in directive', function() {
|
||||
beforeEach(module(function() {
|
||||
directive('syncTest', function(log) {
|
||||
return {
|
||||
link: {
|
||||
pre: function(s, e, attr) { log(attr.test); },
|
||||
post: function(s, e, attr) { log(attr.test); }
|
||||
}
|
||||
};
|
||||
});
|
||||
directive('asyncTest', function(log) {
|
||||
return {
|
||||
templateUrl: 'async.html',
|
||||
link: {
|
||||
pre: function(s, e, attr) { log(attr.test); },
|
||||
post: function(s, e, attr) { log(attr.test); }
|
||||
}
|
||||
};
|
||||
});
|
||||
}));
|
||||
|
||||
beforeEach(inject(function($templateCache) {
|
||||
$templateCache.put('async.html', '<h1>Test</h1>');
|
||||
}));
|
||||
|
||||
it('should provide post-digest value in synchronous directive link functions when after overridden attribute',
|
||||
inject(function(log, $rootScope, $compile) {
|
||||
$rootScope.test = "TEST";
|
||||
element = $compile('<div sync-test test="123" ng-attr-test="{{test}}"></div>')($rootScope);
|
||||
expect(element.attr('test')).toBe('123');
|
||||
expect(log.toArray()).toEqual(['TEST', 'TEST']);
|
||||
}));
|
||||
|
||||
it('should provide post-digest value in synchronous directive link functions when before overridden attribute',
|
||||
inject(function(log, $rootScope, $compile) {
|
||||
$rootScope.test = "TEST";
|
||||
element = $compile('<div sync-test ng-attr-test="{{test}}" test="123"></div>')($rootScope);
|
||||
expect(element.attr('test')).toBe('123');
|
||||
expect(log.toArray()).toEqual(['TEST', 'TEST']);
|
||||
}));
|
||||
|
||||
|
||||
it('should provide post-digest value in asynchronous directive link functions when after overridden attribute',
|
||||
inject(function(log, $rootScope, $compile) {
|
||||
$rootScope.test = "TEST";
|
||||
element = $compile('<div async-test test="123" ng-attr-test="{{test}}"></div>')($rootScope);
|
||||
expect(element.attr('test')).toBe('123');
|
||||
$rootScope.$digest();
|
||||
expect(log.toArray()).toEqual(['TEST', 'TEST']);
|
||||
}));
|
||||
|
||||
it('should provide post-digest value in asynchronous directive link functions when before overridden attribute',
|
||||
inject(function(log, $rootScope, $compile) {
|
||||
$rootScope.test = "TEST";
|
||||
element = $compile('<div async-test ng-attr-test="{{test}}" test="123"></div>')($rootScope);
|
||||
expect(element.attr('test')).toBe('123');
|
||||
$rootScope.$digest();
|
||||
expect(log.toArray()).toEqual(['TEST', 'TEST']);
|
||||
}));
|
||||
});
|
||||
|
||||
it('should work with different prefixes', inject(function($compile, $rootScope) {
|
||||
$rootScope.name = "Misko";
|
||||
|
||||
Reference in New Issue
Block a user