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

Commit 9b17be7

Browse files
committed
fix($compile): use the correct namespace for transcluded svg elements
This fixes the case when a directive that uses `templateUrl` is used inside of a transcluding directive like `ng-repeat`. Fixes #8808
1 parent 3be00df commit 9b17be7

File tree

2 files changed

+44
-8
lines changed

2 files changed

+44
-8
lines changed

src/ng/compile.js

+11-8
Original file line numberDiff line numberDiff line change
@@ -891,22 +891,26 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
891891
maxPriority, ignoreDirective, previousCompileContext);
892892
safeAddClass($compileNodes, 'ng-scope');
893893
var namespace = null;
894+
var namespaceAdaptedCompileNodes = $compileNodes;
894895
return function publicLinkFn(scope, cloneConnectFn, transcludeControllers, parentBoundTranscludeFn, futureParentElement){
895896
assertArg(scope, 'scope');
896897
if (!namespace) {
897898
namespace = detectNamespaceForChildElements(futureParentElement);
898-
if (namespace !== 'html') {
899-
$compileNodes = jqLite(
900-
wrapTemplate(namespace, jqLite('<div>').append($compileNodes).html())
901-
);
902-
}
899+
}
900+
if (namespace !== 'html' && !$compileNodes[0]['$$namespace']) {
901+
namespaceAdaptedCompileNodes = jqLite(
902+
wrapTemplate(namespace, jqLite('<div>').append($compileNodes).html())
903+
);
904+
// When using a directive with replace:true and templateUrl the $compileNodes
905+
// might change, so we need to recreate the namespace adapted compileNodes.
906+
$compileNodes[0]['$$namespace'] = namespace;
903907
}
904908

905909
// important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
906910
// and sometimes changes the structure of the DOM.
907911
var $linkNode = cloneConnectFn
908-
? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
909-
: $compileNodes;
912+
? JQLitePrototype.clone.call(namespaceAdaptedCompileNodes) // IMPORTANT!!!
913+
: namespaceAdaptedCompileNodes;
910914

911915
if (transcludeControllers) {
912916
for (var controllerName in transcludeControllers) {
@@ -1888,7 +1892,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
18881892
// it was cloned therefore we have to clone as well.
18891893
linkNode = jqLiteClone(compileNode);
18901894
}
1891-
18921895
replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
18931896

18941897
// Copy in CSS classes from original node

test/ng/compileSpec.js

+33
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,39 @@ describe('$compile', function() {
289289

290290
}));
291291

292+
it('should support directives with SVG templates and a slow url '+
293+
'that are stamped out later by a transcluding directive', function() {
294+
module(function() {
295+
directive('svgCircleUrl', valueFn({
296+
replace: true,
297+
templateUrl: 'template.html',
298+
templateNamespace: 'SVG',
299+
}));
300+
});
301+
inject(function($compile, $rootScope, $httpBackend) {
302+
$httpBackend.expect('GET', 'template.html').respond('<circle></circle>');
303+
element = $compile('<svg><svg-circle-url ng-repeat="l in list"/></svg>')($rootScope);
304+
305+
// initially the template is not yet loaded
306+
$rootScope.$apply(function() {
307+
$rootScope.list = [1];
308+
});
309+
expect(element.find('svg-circle-url').length).toBe(1);
310+
expect(element.find('circle').length).toBe(0);
311+
312+
// template is loaded and replaces the existing nodes
313+
$httpBackend.flush();
314+
expect(element.find('svg-circle-url').length).toBe(0);
315+
expect(element.find('circle').length).toBe(1);
316+
317+
// new entry should immediately use the loaded template
318+
$rootScope.$apply(function() {
319+
$rootScope.list.push(2);
320+
});
321+
expect(element.find('svg-circle-url').length).toBe(0);
322+
expect(element.find('circle').length).toBe(2);
323+
});
324+
});
292325
});
293326

294327

0 commit comments

Comments
 (0)