Skip to content

Commit 312a3be

Browse files
chrisirhcOron Nadiv
authored and
Oron Nadiv
committed
fix(tooltip): memory leak on show/hide
Create a new child scope and retain a reference to it so that it can be destroyed when the tooltip DOM is removed. Fixes angular-ui#2709 Closes angular-ui#2919
1 parent 876991a commit 312a3be

File tree

2 files changed

+12
-6
lines changed

2 files changed

+12
-6
lines changed

src/tooltip/test/tooltip.spec.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -148,19 +148,19 @@ describe('tooltip', function() {
148148
expect( elmBody.children().length ).toBe( 0 );
149149
}));
150150

151-
it('issue 1191 - isolate scope on the popup should always be child of correct element scope', function () {
151+
it('issue 1191 - scope on the popup should always be child of correct element scope', function () {
152152
var ttScope;
153153
elm.trigger( 'mouseenter' );
154154

155-
ttScope = angular.element( elmBody.children()[1] ).isolateScope();
155+
ttScope = angular.element( elmBody.children()[1] ).scope();
156156
expect( ttScope.$parent ).toBe( tooltipScope );
157157

158158
elm.trigger( 'mouseleave' );
159159

160160
// After leaving and coming back, the scope's parent should be the same
161161
elm.trigger( 'mouseenter' );
162162

163-
ttScope = angular.element( elmBody.children()[1] ).isolateScope();
163+
ttScope = angular.element( elmBody.children()[1] ).scope();
164164
expect( ttScope.$parent ).toBe( tooltipScope );
165165

166166
elm.trigger( 'mouseleave' );
@@ -349,7 +349,7 @@ describe('tooltip', function() {
349349
var match = false;
350350

351351
angular.forEach(angular.element.cache, function (item) {
352-
if (item.data && item.data.$isolateScope === tooltipScope) {
352+
if (item.data && item.data.$scope === tooltipScope) {
353353
match = true;
354354
}
355355
});
@@ -369,7 +369,7 @@ describe('tooltip', function() {
369369
tooltipScope = elmScope.$$childTail.$$childTail;
370370
}));
371371

372-
it( 'should not contain a cached reference when visible', inject( function( $timeout ) {
372+
it( 'should not contain a cached reference when not visible', inject( function( $timeout ) {
373373
expect( inCache() ).toBeTruthy();
374374
elmScope.$destroy();
375375
expect( inCache() ).toBeFalsy();

src/tooltip/tooltip.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
112112

113113
return function link ( scope, element, attrs ) {
114114
var tooltip;
115+
var tooltipLinkedScope;
115116
var transitionTimeout;
116117
var popupTimeout;
117118
var appendToBody = angular.isDefined( options.appendToBody ) ? options.appendToBody : false;
@@ -234,7 +235,8 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
234235
if (tooltip) {
235236
removeTooltip();
236237
}
237-
tooltip = tooltipLinker(ttScope);
238+
tooltipLinkedScope = ttScope.$new();
239+
tooltip = tooltipLinker(tooltipLinkedScope);
238240
}
239241

240242
function removeTooltip() {
@@ -243,6 +245,10 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap
243245
tooltip.remove();
244246
tooltip = null;
245247
}
248+
if (tooltipLinkedScope) {
249+
tooltipLinkedScope.$destroy();
250+
tooltipLinkedScope = null;
251+
}
246252
}
247253

248254
function prepareTooltip() {

0 commit comments

Comments
 (0)