From 9246905acc7a41956e1879242617a7421530619c Mon Sep 17 00:00:00 2001 From: Joe Grund Date: Thu, 30 May 2013 14:25:45 -0400 Subject: [PATCH] fix(tooltip): make sure tooltip scope is evicted from cache This fix makes sure the tooltip.$scope is cleared from angular.element.cache when $destroy is called, preventing a memory leak. Closes #484 --- src/tooltip/test/tooltip.spec.js | 40 ++++++++++++++++++++++++++++++++ src/tooltip/tooltip.js | 9 +++---- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/tooltip/test/tooltip.spec.js b/src/tooltip/test/tooltip.spec.js index 75b0df2c86..b5c9c35b17 100644 --- a/src/tooltip/test/tooltip.spec.js +++ b/src/tooltip/test/tooltip.spec.js @@ -238,6 +238,46 @@ describe('tooltip', function() { })); }); + describe('cleanup', function () { + var elmBody, elm, elmScope, tooltipScope; + + function inCache() { + var match = false; + + angular.forEach(angular.element.cache, function (item) { + if (item.data && item.data.$scope === tooltipScope) { + match = true; + } + }); + + return match; + } + + beforeEach(inject(function ( $compile, $rootScope ) { + elmBody = angular.element('
'); + + $compile(elmBody)($rootScope); + $rootScope.$apply(); + + elm = elmBody.find('input'); + elmScope = elm.scope(); + tooltipScope = elmScope.$$childTail; + })); + + it( 'should not contain a cached reference', function() { + expect( inCache() ).toBeTruthy(); + elmScope.$destroy(); + expect( inCache() ).toBeFalsy(); + }); + + it( 'should not contain a cached reference when visible', inject( function( $timeout ) { + expect( inCache() ).toBeTruthy(); + elm.trigger('fooTrigger'); + elmScope.$destroy(); + $timeout.flush(); + expect( inCache() ).toBeFalsy(); + })); + }); }); describe('tooltipWithDifferentSymbols', function() { diff --git a/src/tooltip/tooltip.js b/src/tooltip/tooltip.js index 3803820226..5504e581f3 100644 --- a/src/tooltip/tooltip.js +++ b/src/tooltip/tooltip.js @@ -303,12 +303,13 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] ) } }); } - - // if this trigger element is destroyed while the tooltip is open, we - // need to close the tooltip. - scope.$on('$destroy', function closeTooltipOnDestroy () { + + // Make sure tooltip is destroyed and removed. + scope.$on('$destroy', function onDestroyTooltip() { if ( scope.tt_isOpen ) { hide(); + } else { + tooltip.remove(); } }); }