Skip to content

Commit

Permalink
fix(tooltip): open tooltip correctly from lifecycle hooks
Browse files Browse the repository at this point in the history
Fixes #3130
  • Loading branch information
maxokorokov committed Apr 30, 2019
1 parent 7dd5168 commit 80beb3a
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 3 deletions.
28 changes: 26 additions & 2 deletions src/tooltip/tooltip.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@ import {TestBed, ComponentFixture, inject, fakeAsync, tick} from '@angular/core/
import {createGenericTestComponent, createKeyEvent} from '../test/common';

import {By} from '@angular/platform-browser';
import {Component, ViewChild, ChangeDetectionStrategy, TemplateRef, ViewContainerRef} from '@angular/core';
import {
Component,
ViewChild,
ChangeDetectionStrategy,
TemplateRef,
ViewContainerRef,
AfterViewInit
} from '@angular/core';

import {Key} from '../util/key';

Expand Down Expand Up @@ -58,7 +65,8 @@ describe('ngb-tooltip-window', () => {
describe('ngb-tooltip', () => {

beforeEach(() => {
TestBed.configureTestingModule({declarations: [TestComponent, TestOnPushComponent], imports: [NgbTooltipModule]});
TestBed.configureTestingModule(
{declarations: [TestComponent, TestOnPushComponent, TestHooksComponent], imports: [NgbTooltipModule]});
});

function getWindow(element) { return element.querySelector('ngb-tooltip-window'); }
Expand Down Expand Up @@ -239,6 +247,15 @@ describe('ngb-tooltip', () => {
expect(getWindow(fixture.nativeElement)).toBeNull();
});

it('should open tooltip from hooks', () => {
const fixture = TestBed.createComponent(TestHooksComponent);
fixture.detectChanges();

const tooltipWindow = fixture.debugElement.query(By.directive(NgbTooltipWindow));
expect(tooltipWindow.nativeElement).toHaveCssClass('tooltip');
expect(tooltipWindow.nativeElement).toHaveCssClass('show');
});

describe('positioning', () => {

it('should use requested position', () => {
Expand Down Expand Up @@ -639,3 +656,10 @@ export class TestComponent {
@Component({selector: 'test-onpush-cmpt', changeDetection: ChangeDetectionStrategy.OnPush, template: ``})
export class TestOnPushComponent {
}

@Component({selector: 'test-hooks', template: `<div ngbTooltip="tooltip"></div>`})
export class TestHooksComponent implements AfterViewInit {
@ViewChild(NgbTooltip) tooltip;

ngAfterViewInit() { this.tooltip.open(); }
}
11 changes: 10 additions & 1 deletion src/tooltip/tooltip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,16 @@ export class NgbTooltip implements OnInit, OnDestroy {
this._document.querySelector(this.container).appendChild(this._windowRef.location.nativeElement);
}

// apply styling to set basic css-classes on target element, before going for positioning
// We need to detect changes, because we don't know where .open() might be called from.
// Ex. opening tooltip from one of lifecycle hooks that run after the CD
// (say from ngAfterViewInit) will result in 'ExpressionHasChanged' exception
this._windowRef.changeDetectorRef.detectChanges();

// We need to mark for check, because tooltip won't work inside the OnPush component.
// Ex. when we use expression like `{{ tooltip.isOpen() : 'opened' : 'closed' }}`
// inside the template of an OnPush component and we change the tooltip from
// open -> closed, the expression in question won't be updated unless we explicitly
// mark the parent component to be checked.
this._windowRef.changeDetectorRef.markForCheck();

ngbAutoClose(
Expand Down

0 comments on commit 80beb3a

Please sign in to comment.