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

Commit d44e5d3

Browse files
committed
refactor($compile): allow transclude data to be GCed after a non-cloning transclusion
1 parent 7ffb2d3 commit d44e5d3

File tree

2 files changed

+31
-4
lines changed

2 files changed

+31
-4
lines changed

src/ng/compile.js

+13-4
Original file line numberDiff line numberDiff line change
@@ -2205,6 +2205,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
22052205
// This is the function that is injected as `$transclude`.
22062206
// Note: all arguments are optional!
22072207
function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement, slotName) {
2208+
if (!boundTranscludeFn) {
2209+
throw $compileMinErr('multitransclude', 'This element has already been transcluded.');
2210+
}
2211+
22082212
var transcludeControllers;
22092213
// No scope passed in:
22102214
if (!isScope(scope)) {
@@ -2221,16 +2225,21 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
22212225
futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element;
22222226
}
22232227
if (slotName) {
2224-
var slotTranscludeFn = boundTranscludeFn.$$slots[slotName];
2225-
if (!slotTranscludeFn) {
2228+
boundTranscludeFn = boundTranscludeFn.$$slots[slotName];
2229+
if (!boundTranscludeFn) {
22262230
throw $compileMinErr('noslot',
22272231
'No parent directive that requires a transclusion with slot name "{0}". ' +
22282232
'Element: {1}',
22292233
slotName, startingTag($element));
22302234
}
2231-
return slotTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
22322235
}
2233-
return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
2236+
2237+
var res = boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
2238+
//Clear references not required if this transcluded the original nodes
2239+
if (!cloneAttachFn) {
2240+
boundTranscludeFn = scopeToChild = elementControllers = $element = null;
2241+
}
2242+
return res;
22342243
}
22352244
}
22362245
}

test/ng/compileSpec.js

+18
Original file line numberDiff line numberDiff line change
@@ -6015,6 +6015,24 @@ describe('$compile', function() {
60156015
});
60166016

60176017

6018+
it('should throw if a transcluded node is transcluded again', function() {
6019+
module(function() {
6020+
directive('trans', valueFn({
6021+
transclude: true,
6022+
link: function(scope, element, attr, ctrl, $transclude) {
6023+
$transclude();
6024+
$transclude();
6025+
}
6026+
}));
6027+
});
6028+
inject(function($rootScope, $compile) {
6029+
expect(function() {
6030+
$compile('<trans></trans>')($rootScope);
6031+
}).toThrowMinErr('$compile', 'multitransclude', 'This element has already been transcluded.');
6032+
});
6033+
});
6034+
6035+
60186036
it('should not leak if two "element" transclusions are on the same element (with debug info)', function() {
60196037
if (jQuery) {
60206038
// jQuery 2.x doesn't expose the cache storage.

0 commit comments

Comments
 (0)