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

fix($compile): link async+replace element transclusion directives with comment element #6101

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions src/ng/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -1142,7 +1142,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
templateDirective = previousCompileContext.templateDirective,
nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
hasTranscludeDirective = false,
hasElementTranscludeDirective = false,
hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
$compileNode = templateAttrs.$$element = jqLite(compileNode),
directive,
directiveName,
Expand Down Expand Up @@ -1316,6 +1316,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {

nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
nodeLinkFn.transclude = hasTranscludeDirective && childTranscludeFn;
previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;

// might be normal or delayed nodeLinkFn depending on if templateUrl is present
return nodeLinkFn;
Expand Down Expand Up @@ -1712,8 +1713,13 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {

if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
var oldClasses = beforeTemplateLinkNode.className;
// it was cloned therefore we have to clone as well.
linkNode = jqLiteClone(compileNode);

if (!(previousCompileContext.hasElementTranscludeDirective &&
origAsyncDirective.replace)) {
// 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
Expand Down
51 changes: 51 additions & 0 deletions test/ng/compileSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3972,6 +3972,57 @@ describe('$compile', function() {
});
});

// issue #6006
it('should link directive with $element as a comment node', function() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this test is huge... It would be smaller if the directive definitions weren't there, so they could be moved outside... But I like the locality of reference like this.

I don't totally know if this is the right test for this though. It does work, but I'm not sure if this fix will work in all possible configurations. This is a bit tricky. Some help with this would be awesome.

module(function($provide) {
directive('innerAgain', function(log) {
return {
transclude: 'element',
link: function(scope, element, attr, controllers, transclude) {
log('innerAgain:'+lowercase(nodeName_(element))+':'+trim(element[0].data));
transclude(scope, function(clone) {
element.parent().append(clone);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

behaviour similar to ngIf

});
}
};
});
directive('inner', function(log) {
return {
replace: true,
templateUrl: 'inner.html',
link: function(scope, element) {
log('inner:'+lowercase(nodeName_(element))+':'+trim(element[0].data));
}
};
});
directive('outer', function(log) {
return {
transclude: 'element',
link: function(scope, element, attrs, controllers, transclude) {
log('outer:'+lowercase(nodeName_(element))+':'+trim(element[0].data));
transclude(scope, function(clone) {
element.parent().append(clone);
});
}
};
});
});
inject(function(log, $compile, $rootScope, $templateCache) {
$templateCache.put('inner.html', '<div inner-again><p>Content</p></div>');
element = $compile('<div><div outer><div inner></div></div></div>')($rootScope);
$rootScope.$digest();
var child = element.children();

expect(log.toArray()).toEqual([
"outer:#comment:outer:",
"innerAgain:#comment:innerAgain:",
"inner:#comment:innerAgain:"]);
expect(child.length).toBe(1);
expect(child.contents().length).toBe(2);
expect(lowercase(nodeName_(child.contents().eq(0)))).toBe('#comment');
expect(lowercase(nodeName_(child.contents().eq(1)))).toBe('div');
});
});
});

it('should safely create transclude comment node and not break with "-->"',
Expand Down