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
Closes #8816
This commit is contained in:
Tobias Bosch
2014-08-28 11:47:41 -07:00
parent 49455a75dc
commit cb73a37c7c
2 changed files with 46 additions and 11 deletions

View File

@@ -955,26 +955,29 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
var compositeLinkFn =
compileNodes($compileNodes, transcludeFn, $compileNodes,
maxPriority, ignoreDirective, previousCompileContext);
compile.$$addScopeClass($compileNodes);
var namespace = null;
var namespaceAdaptedCompileNodes = $compileNodes;
var lastCompileNode;
return function publicLinkFn(scope, cloneConnectFn, transcludeControllers, parentBoundTranscludeFn, futureParentElement){
var namespace = null;
assertArg(scope, 'scope');
if (!namespace) {
namespace = detectNamespaceForChildElements(futureParentElement);
if (namespace !== 'html') {
$compileNodes = jqLite(
wrapTemplate(namespace, jqLite('<div>').append($compileNodes).html())
);
}
}
if (namespace !== 'html' && $compileNodes[0] !== lastCompileNode) {
namespaceAdaptedCompileNodes = jqLite(
wrapTemplate(namespace, jqLite('<div>').append($compileNodes).html())
);
}
// When using a directive with replace:true and templateUrl the $compileNodes
// might change, so we need to recreate the namespace adapted compileNodes.
lastCompileNode = $compileNodes[0];
// important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
// and sometimes changes the structure of the DOM.
var $linkNode = cloneConnectFn
? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
: $compileNodes;
? JQLitePrototype.clone.call(namespaceAdaptedCompileNodes) // IMPORTANT!!!
: namespaceAdaptedCompileNodes;
if (transcludeControllers) {
for (var controllerName in transcludeControllers) {
@@ -1940,7 +1943,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
// it was cloned therefore we have to clone as well.
linkNode = jqLiteClone(compileNode);
}
replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
// Copy in CSS classes from original node

View File

@@ -289,6 +289,39 @@ describe('$compile', function() {
}));
it('should support directives with SVG templates and a slow url '+
'that are stamped out later by a transcluding directive', function() {
module(function() {
directive('svgCircleUrl', valueFn({
replace: true,
templateUrl: 'template.html',
templateNamespace: 'SVG',
}));
});
inject(function($compile, $rootScope, $httpBackend) {
$httpBackend.expect('GET', 'template.html').respond('<circle></circle>');
element = $compile('<svg><svg-circle-url ng-repeat="l in list"/></svg>')($rootScope);
// initially the template is not yet loaded
$rootScope.$apply(function() {
$rootScope.list = [1];
});
expect(element.find('svg-circle-url').length).toBe(1);
expect(element.find('circle').length).toBe(0);
// template is loaded and replaces the existing nodes
$httpBackend.flush();
expect(element.find('svg-circle-url').length).toBe(0);
expect(element.find('circle').length).toBe(1);
// new entry should immediately use the loaded template
$rootScope.$apply(function() {
$rootScope.list.push(2);
});
expect(element.find('svg-circle-url').length).toBe(0);
expect(element.find('circle').length).toBe(2);
});
});
});