fix($compile): don't add merged attributes twice to $attrs

In replace directives, attribute values from the template are added twice
to the replaced element when both the replaced element and the template
element have the attribute. This does not affect the DOM, as it normalizes
duplicate values. The values are however duplicated in the $attrs object
that is available to directive link functions.

Fixes #8159
Closes #14737
This commit is contained in:
Martin Staffa
2016-06-09 15:32:08 +02:00
committed by Peter Bacon Darwin
parent 78a23ccea2
commit 3ba29c464d
2 changed files with 32 additions and 11 deletions
+9 -11
View File
@@ -2761,18 +2761,16 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
// copy the new attributes on the old attrs object
forEach(src, function(value, key) {
if (key === 'class') {
safeAddClass($element, value);
dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
} else if (key === 'style') {
$element.attr('style', $element.attr('style') + ';' + value);
dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
// `dst` will never contain hasOwnProperty as DOM parser won't let it.
// You will get an "InvalidCharacterError: DOM Exception 5" error if you
// have an attribute like "has-own-property" or "data-has-own-property", etc.
} else if (key.charAt(0) !== '$' && !dst.hasOwnProperty(key)) {
// Check if we already set this attribute in the loop above.
// `dst` will never contain hasOwnProperty as DOM parser won't let it.
// You will get an "InvalidCharacterError: DOM Exception 5" error if you
// have an attribute like "has-own-property" or "data-has-own-property", etc.
if (!dst.hasOwnProperty(key) && key.charAt(0) !== '$') {
dst[key] = value;
dstAttr[key] = srcAttr[key];
if (key !== 'class' && key !== 'style') {
dstAttr[key] = srcAttr[key];
}
}
});
}
+23
View File
@@ -980,6 +980,29 @@ describe('$compile', function() {
}));
it('should not set merged attributes twice in $attrs', function() {
var attrs;
module(function() {
directive('logAttrs', function() {
return {
link: function($scope, $element, $attrs) {
attrs = $attrs;
}
};
});
});
inject(function($compile, $rootScope) {
element = $compile(
'<div><div log-attrs replace class="myLog"></div><div>')($rootScope);
var div = element.find('div');
expect(div.attr('class')).toBe('myLog log');
expect(attrs.class).toBe('myLog log');
});
});
it('should prevent multiple templates per element', inject(function($compile) {
try {
$compile('<div><span replace class="replace"></span></div>');