mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(tooltip): wrong position when using OnPush change detection (#3671)
* fix(tooltip): wrong position when using OnPush change detection Fixes the tooltip having a wrong position if it is inside a component with `OnPush` change detection. The issue was due to the fact that when `OnPush` is used, the tooltip text isn't rendered at the moment when the element is positioned. Fixes #3497.
This commit is contained in:
committed by
Jeremy Elbourn
parent
3796f69f9d
commit
edf01c025e
@@ -35,7 +35,7 @@ describe('MdTooltip', () => {
|
||||
imports: [MdTooltipModule.forRoot(), OverlayModule, NoopAnimationsModule],
|
||||
declarations: [BasicTooltipDemo, ScrollableTooltipDemo, OnPushTooltipDemo],
|
||||
providers: [
|
||||
Platform,
|
||||
{provide: Platform, useValue: {IOS: false}},
|
||||
{provide: OverlayContainer, useFactory: () => {
|
||||
overlayContainerElement = document.createElement('div');
|
||||
document.body.appendChild(overlayContainerElement);
|
||||
@@ -411,7 +411,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
|
||||
@@ -433,6 +433,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', () => {
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
OnDestroy,
|
||||
Renderer,
|
||||
OnInit,
|
||||
ChangeDetectorRef
|
||||
ChangeDetectorRef,
|
||||
} from '@angular/core';
|
||||
import {
|
||||
style,
|
||||
@@ -157,7 +157,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());
|
||||
@@ -313,6 +313,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();
|
||||
@@ -394,8 +396,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);
|
||||
}
|
||||
|
||||
@@ -415,7 +417,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);
|
||||
}
|
||||
|
||||
@@ -441,8 +443,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);
|
||||
}
|
||||
}
|
||||
@@ -463,4 +465,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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user