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

Commit a5ff651

Browse files
fix($compile): support merging special attribute names in replace directives
When compiling a `replace` directive, the compiler merges the attributes from the replaced element onto the template element. Unfortunately, `setAttribute` and other related DOM methods do not allow certain attribute names - in particular Angular 2 style names such as `(click)` and `[value]`. This is relevant when using ngForward with Angular Material, since the `mgButton` directive uses `replace` and in the former you often use `(click)`. This fixes the problem but for those special attributes the speed is considerably slow. Closes #13317 Closes #13318
1 parent ccd47ec commit a5ff651

File tree

2 files changed

+30
-1
lines changed

2 files changed

+30
-1
lines changed

Diff for: src/ng/compile.js

+19-1
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
989989
function($injector, $interpolate, $exceptionHandler, $templateRequest, $parse,
990990
$controller, $rootScope, $document, $sce, $animate, $$sanitizeUri) {
991991

992+
var SIMPLE_ATTR_NAME = /^\w/;
993+
var specialAttrHolder = document.createElement('div');
992994
var Attributes = function(element, attributesToCopy) {
993995
if (attributesToCopy) {
994996
var keys = Object.keys(attributesToCopy);
@@ -1168,7 +1170,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
11681170
if (value === null || isUndefined(value)) {
11691171
this.$$element.removeAttr(attrName);
11701172
} else {
1171-
this.$$element.attr(attrName, value);
1173+
if (SIMPLE_ATTR_NAME.test(attrName)) {
1174+
this.$$element.attr(attrName, value);
1175+
} else {
1176+
setSpecialAttr(this.$$element[0], attrName, value);
1177+
}
11721178
}
11731179
}
11741180

@@ -1221,6 +1227,18 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
12211227
}
12221228
};
12231229

1230+
function setSpecialAttr(element, attrName, value) {
1231+
// Attributes names that do not start with letters (such as `(click)`) cannot be set using `setAttribute`
1232+
// so we have to jump through some hoops to get such an attribute
1233+
// https://github.com/angular/angular.js/pull/13318
1234+
specialAttrHolder.innerHTML = "<span " + attrName + ">";
1235+
var attributes = specialAttrHolder.firstChild.attributes;
1236+
var attribute = attributes[0];
1237+
// We have to remove the attribute from its container element before we can add it to the destination element
1238+
attributes.removeNamedItem(attribute.name);
1239+
attribute.value = value;
1240+
element.attributes.setNamedItem(attribute);
1241+
}
12241242

12251243
function safeAddClass($element, className) {
12261244
try {

Diff for: test/ng/compileSpec.js

+11
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,17 @@ describe('$compile', function() {
868868
expect(div.attr('id')).toEqual('myid');
869869
}));
870870

871+
872+
it('should correctly merge attributes that contain special characters', inject(function($compile, $rootScope) {
873+
element = $compile(
874+
'<div><div replace (click)="doSomething()" [value]="someExpression" ω="omega"></div><div>')($rootScope);
875+
var div = element.find('div');
876+
expect(div.attr('(click)')).toEqual('doSomething()');
877+
expect(div.attr('[value]')).toEqual('someExpression');
878+
expect(div.attr('ω')).toEqual('omega');
879+
}));
880+
881+
871882
it('should prevent multiple templates per element', inject(function($compile) {
872883
try {
873884
$compile('<div><span replace class="replace"></span></div>');

0 commit comments

Comments
 (0)