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

fix($compile): allow compile data to be GCed after a non-clone linking #13422

Merged
merged 1 commit into from
Aug 30, 2016
Merged
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
27 changes: 27 additions & 0 deletions docs/content/error/$compile/multilink.ngdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
@ngdoc error
@name $compile:multilink
@fullName Linking Element Multiple Times
@description

This error occurs when a single element is linked more then once.

For example, if an element is compiled and linked twice without cloning:
```
var linker = $compile(template);
linker($scope); //=> ok
linker($scope); //=> multilink error
```

Linking an element as a clone multiple times is ok:
```
var linker = $compile(template);
linker($scope, function() { ... }); //=> ok
linker($scope, function() { ... }); //=> ok
```

However once an element has been linked it can not be re-linked as a clone:
```
var linker = $compile(template);
linker($scope); //=> ok
linker($scope, function() { ... }); //=> multilink error
```
7 changes: 7 additions & 0 deletions src/ng/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -1817,6 +1817,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
compile.$$addScopeClass($compileNodes);
var namespace = null;
return function publicLinkFn(scope, cloneConnectFn, options) {
if (!$compileNodes) {
throw $compileMinErr('multilink', 'This element has already been linked.');
}
assertArg(scope, 'scope');

if (previousCompileContext && previousCompileContext.needsNewScope) {
Expand Down Expand Up @@ -1871,6 +1874,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {

if (cloneConnectFn) cloneConnectFn($linkNode, scope);
if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);

if (!cloneConnectFn) {
$compileNodes = compositeLinkFn = null;
}
return $linkNode;
};
}
Expand Down
29 changes: 27 additions & 2 deletions test/ng/compileSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3631,6 +3631,14 @@ describe('$compile', function() {
expect(element.text()).toBe('3');
});
});

it('should throw multilink error when linking the same element more then once', function() {
var linker = $compile('<div>');
linker($rootScope).remove();
expect(function() {
linker($rootScope);
}).toThrowMinErr('$compile', 'multilink', 'This element has already been linked.');
});
});


Expand Down Expand Up @@ -7971,6 +7979,22 @@ describe('$compile', function() {
});
});

it('should throw if a transcluded node is transcluded again', function() {
module(function() {
directive('trans', valueFn({
transclude: true,
link: function(scope, element, attr, ctrl, $transclude) {
$transclude();
$transclude();
}
}));
});
inject(function($rootScope, $compile) {
expect(function() {
$compile('<trans></trans>')($rootScope);
}).toThrowMinErr('$compile', 'multilink', 'This element has already been linked.');
});
});

it('should not leak if two "element" transclusions are on the same element (with debug info)', function() {
if (jQuery) {
Expand Down Expand Up @@ -8113,7 +8137,7 @@ describe('$compile', function() {
'</div>' +
'</div>' +
'</div>');
element = template($rootScope);
element = template($rootScope, noop);
$rootScope.$digest();
$timeout.flush();
$httpBackend.flush();
Expand All @@ -8123,10 +8147,11 @@ describe('$compile', function() {
$templateCache.removeAll();
var destroyedScope = $rootScope.$new();
destroyedScope.$destroy();
var clone = template(destroyedScope);
var clone = template(destroyedScope, noop);
$rootScope.$digest();
$timeout.flush();
expect(linkFn).not.toHaveBeenCalled();
clone.remove();
});
});

Expand Down