diff --git a/src/lib/tooltip/tooltip.html b/src/lib/tooltip/tooltip.html index 0e43808a15c7..7bcb5e437d3f 100644 --- a/src/lib/tooltip/tooltip.html +++ b/src/lib/tooltip/tooltip.html @@ -1,6 +1,6 @@
+ (@state.done)="_afterVisibilityAnimation($event)"> {{message}}
\ No newline at end of file diff --git a/src/lib/tooltip/tooltip.spec.ts b/src/lib/tooltip/tooltip.spec.ts index d1d8b4fe175a..e5c9d2910b36 100644 --- a/src/lib/tooltip/tooltip.spec.ts +++ b/src/lib/tooltip/tooltip.spec.ts @@ -2,7 +2,7 @@ import { async, ComponentFixture, TestBed, tick, fakeAsync, flushMicrotasks } from '@angular/core/testing'; -import {Component, DebugElement} from '@angular/core'; +import {Component, DebugElement, AnimationTransitionEvent} from '@angular/core'; import {By} from '@angular/platform-browser'; import {TooltipPosition, MdTooltip, TOOLTIP_HIDE_DELAY, MdTooltipModule} from './tooltip'; import {OverlayContainer} from '../core'; @@ -123,14 +123,45 @@ describe('MdTooltip', () => { expect(overlayContainerElement.childNodes.length).toBe(0); expect(overlayContainerElement.textContent).toBe(''); }); + + it('should not try to dispose the tooltip when destroyed and done hiding', fakeAsync(() => { + tooltipDirective.show(); + fixture.detectChanges(); + tick(150); + + tooltipDirective.hide(); + tick(TOOLTIP_HIDE_DELAY); // Change the tooltip state to hidden and trigger animation start + + // Store the tooltip instance, which will be set to null after the button is hidden. + const tooltipInstance = tooltipDirective._tooltipInstance; + fixture.componentInstance.showButton = false; + fixture.detectChanges(); + + // At this point the animation should be able to complete itself and trigger the + // _afterVisibilityAnimation function, but for unknown reasons in the test infrastructure, + // this does not occur. Manually call this and verify that doing so does not + // throw an error. + tooltipInstance._afterVisibilityAnimation(new AnimationTransitionEvent({ + fromState: 'visible', + toState: 'hidden', + totalTime: 150, + phaseName: '', + })); + })); }); }); @Component({ selector: 'app', - template: `` + template: ` + ` }) class BasicTooltipDemo { position: TooltipPosition = 'below'; message: string = initialTooltipMessage; + showButton: boolean = true; } diff --git a/src/lib/tooltip/tooltip.ts b/src/lib/tooltip/tooltip.ts index 8dbde939c30d..1d12825301b5 100644 --- a/src/lib/tooltip/tooltip.ts +++ b/src/lib/tooltip/tooltip.ts @@ -129,7 +129,10 @@ export class MdTooltip { // Dispose the overlay when finished the shown tooltip. this._tooltipInstance.afterHidden().subscribe(() => { - this._disposeTooltip(); + // Check first if the tooltip has already been removed through this components destroy. + if (this._tooltipInstance) { + this._disposeTooltip(); + } }); } @@ -270,7 +273,6 @@ export class TooltipComponent { _afterVisibilityAnimation(e: AnimationTransitionEvent): void { if (e.toState === 'hidden' && !this.isVisible()) { this._onHide.next(); - } }