diff --git a/src/lib/tooltip/tooltip.spec.ts b/src/lib/tooltip/tooltip.spec.ts index a5e3cc932c7d..9381839b6fe9 100644 --- a/src/lib/tooltip/tooltip.spec.ts +++ b/src/lib/tooltip/tooltip.spec.ts @@ -34,7 +34,7 @@ describe('MdTooltip', () => { imports: [MdTooltipModule.forRoot(), OverlayModule], declarations: [BasicTooltipDemo, ScrollableTooltipDemo, OnPushTooltipDemo], providers: [ - Platform, + {provide: Platform, useValue: {IOS: false}}, {provide: OverlayContainer, useFactory: () => { overlayContainerElement = document.createElement('div'); document.body.appendChild(overlayContainerElement); @@ -410,7 +410,7 @@ describe('MdTooltip', () => { fixture.detectChanges(); - // wait till animation has finished + // wait until animation has finished tick(500); // Make sure tooltip is shown to the user and animation has finished @@ -432,6 +432,15 @@ describe('MdTooltip', () => { flushMicrotasks(); expect(tooltipDirective._tooltipInstance).toBeNull(); })); + + it('should have rendered the tooltip text on init', fakeAsync(() => { + dispatchFakeEvent(buttonElement, 'mouseenter'); + fixture.detectChanges(); + tick(0); + + const tooltipElement = overlayContainerElement.querySelector('.mat-tooltip') as HTMLElement; + expect(tooltipElement.textContent).toContain('initial tooltip message'); + })); }); describe('destroy', () => { diff --git a/src/lib/tooltip/tooltip.ts b/src/lib/tooltip/tooltip.ts index cc13061eb92c..d4116e786b69 100644 --- a/src/lib/tooltip/tooltip.ts +++ b/src/lib/tooltip/tooltip.ts @@ -15,7 +15,7 @@ import { OnDestroy, Renderer, OnInit, - ChangeDetectorRef + ChangeDetectorRef, } from '@angular/core'; import { Overlay, @@ -155,7 +155,7 @@ export class MdTooltip implements OnInit, OnDestroy { @Optional() private _dir: Dir) { // The mouse events shouldn't be bound on iOS devices, because - // they can prevent the first tap from firing it's click event. + // they can prevent the first tap from firing its click event. if (!_platform.IOS) { _renderer.listen(_elementRef.nativeElement, 'mouseenter', () => this.show()); _renderer.listen(_elementRef.nativeElement, 'mouseleave', () => this.hide()); @@ -311,6 +311,8 @@ export class MdTooltip implements OnInit, OnDestroy { // Must wait for the message to be painted to the tooltip so that the overlay can properly // calculate the correct positioning based on the size of the text. this._tooltipInstance.message = message; + this._tooltipInstance._markForCheck(); + this._ngZone.onMicrotaskEmpty.first().subscribe(() => { if (this._tooltipInstance) { this._overlayRef.updatePosition(); @@ -392,8 +394,8 @@ export class TooltipComponent { // Mark for check so if any parent component has set the // ChangeDetectionStrategy to OnPush it will be checked anyways - this._changeDetectorRef.markForCheck(); - setTimeout(() => { this._closeOnInteraction = true; }, 0); + this._markForCheck(); + setTimeout(() => this._closeOnInteraction = true, 0); }, delay); } @@ -413,7 +415,7 @@ export class TooltipComponent { // Mark for check so if any parent component has set the // ChangeDetectionStrategy to OnPush it will be checked anyways - this._changeDetectorRef.markForCheck(); + this._markForCheck(); }, delay); } @@ -439,8 +441,8 @@ export class TooltipComponent { case 'after': this._transformOrigin = isLtr ? 'left' : 'right'; break; case 'left': this._transformOrigin = 'right'; break; case 'right': this._transformOrigin = 'left'; break; - case 'above': this._transformOrigin = 'bottom'; break; - case 'below': this._transformOrigin = 'top'; break; + case 'above': this._transformOrigin = 'bottom'; break; + case 'below': this._transformOrigin = 'top'; break; default: throw new MdTooltipInvalidPositionError(value); } } @@ -461,4 +463,13 @@ export class TooltipComponent { this.hide(0); } } + + /** + * Marks that the tooltip needs to be checked in the next change detection run. + * Mainly used for rendering the initial text before positioning a tooltip, which + * can be problematic in components with OnPush change detection. + */ + _markForCheck(): void { + this._changeDetectorRef.markForCheck(); + } }