Skip to content

Commit 4affc8d

Browse files
committed
fix(tooltip): add IntersectionObserver to remove tooltip when host element is not visible
1 parent f9a0436 commit 4affc8d

File tree

5 files changed

+47
-10
lines changed

5 files changed

+47
-10
lines changed

projects/coreui-angular/src/lib/popover/popover.directive.spec.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { ChangeDetectorRef, ElementRef, Renderer2, ViewContainerRef } from '@angular/core';
2-
import { ListenersService } from '../services/listeners.service';
2+
import { IntersectionService, ListenersService } from '../services';
33
import { PopoverDirective } from './popover.directive';
4-
import { IntersectionService } from '../services';
54

65
describe('PopoverDirective', () => {
76
let document: Document;

projects/coreui-angular/src/lib/services/intersection.service.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Injectable, OnDestroy } from '@angular/core';
22
import { BehaviorSubject } from 'rxjs';
33

4-
interface IIntersectionObserverInit {
4+
export interface IIntersectionObserverInit {
55
root?: Element | null;
66
rootMargin?: string;
77
threshold?: number | number[];
@@ -26,7 +26,7 @@ export class IntersectionService implements OnDestroy {
2626

2727
createIntersectionObserver(hostElement: { nativeElement: Element; }, observerOptions = this.defaultObserverOptions) {
2828

29-
const options = { ...this.defaultObserverOptions, ...observerOptions }
29+
const options = { ...this.defaultObserverOptions, ...observerOptions };
3030

3131
this.hostElement = hostElement;
3232

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1-
export { IntersectionService } from './intersection.service';
1+
export { IntersectionService, IIntersectionObserverInit } from './intersection.service';
2+
export { ListenersService, IListenersConfig } from './listeners.service';
23
export { ClassToggleService } from './class-toggle.service';

projects/coreui-angular/src/lib/tooltip/tooltip.directive.spec.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { ChangeDetectorRef, ElementRef, Renderer2, ViewContainerRef } from '@angular/core';
2-
import { ListenersService } from '../services/listeners.service';
2+
import { IntersectionService, ListenersService } from '../services';
33
import { TooltipDirective } from './tooltip.directive';
44

55
describe('TooltipDirective', () => {
@@ -11,7 +11,16 @@ describe('TooltipDirective', () => {
1111

1212
it('should create an instance', () => {
1313
const listenersService = new ListenersService(renderer);
14-
const directive = new TooltipDirective(document, renderer, hostElement, viewContainerRef, listenersService, changeDetectorRef);
14+
const intersectionService = new IntersectionService();
15+
const directive = new TooltipDirective(
16+
document,
17+
renderer,
18+
hostElement,
19+
viewContainerRef,
20+
listenersService,
21+
changeDetectorRef,
22+
intersectionService
23+
);
1524
expect(directive).toBeTruthy();
1625
});
1726
});

projects/coreui-angular/src/lib/tooltip/tooltip.directive.ts

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
AfterViewInit,
23
ChangeDetectorRef,
34
ComponentRef,
45
Directive,
@@ -15,19 +16,22 @@ import {
1516
ViewContainerRef
1617
} from '@angular/core';
1718
import { DOCUMENT } from '@angular/common';
19+
import { Subscription } from 'rxjs';
20+
import { debounceTime } from 'rxjs/operators';
1821
import { createPopper, Instance, Options } from '@popperjs/core';
1922

2023
import { Triggers } from '../coreui.types';
2124
import { TooltipComponent } from './tooltip/tooltip.component';
2225
import { IListenersConfig, ListenersService } from '../services/listeners.service';
26+
import { IntersectionService } from '../services';
2327

2428
@Directive({
2529
selector: '[cTooltip]',
2630
exportAs: 'cTooltip',
27-
providers: [ListenersService],
31+
providers: [ListenersService, IntersectionService],
2832
standalone: true
2933
})
30-
export class TooltipDirective implements OnChanges, OnDestroy, OnInit {
34+
export class TooltipDirective implements OnChanges, OnDestroy, OnInit, AfterViewInit {
3135

3236
/**
3337
* Content of tooltip
@@ -92,15 +96,23 @@ export class TooltipDirective implements OnChanges, OnDestroy, OnInit {
9296
]
9397
};
9498

99+
private intersectingSubscription?: Subscription;
100+
95101
constructor(
96102
@Inject(DOCUMENT) private document: Document,
97103
private renderer: Renderer2,
98104
private hostElement: ElementRef,
99105
private viewContainerRef: ViewContainerRef,
100106
private listenersService: ListenersService,
101-
private changeDetectorRef: ChangeDetectorRef
107+
private changeDetectorRef: ChangeDetectorRef,
108+
private intersectionService: IntersectionService
102109
) {}
103110

111+
ngAfterViewInit(): void {
112+
this.intersectionService.createIntersectionObserver(this.hostElement);
113+
this.intersectionServiceSubscribe();
114+
}
115+
104116
ngOnChanges(changes: SimpleChanges): void {
105117
if (changes['visible']) {
106118
changes['visible'].currentValue ? this.addTooltipElement() : this.removeTooltipElement();
@@ -110,6 +122,7 @@ export class TooltipDirective implements OnChanges, OnDestroy, OnInit {
110122
ngOnDestroy(): void {
111123
this.clearListeners();
112124
this.destroyTooltipElement();
125+
this.intersectionServiceSubscribe(false);
113126
}
114127

115128
ngOnInit(): void {
@@ -140,6 +153,21 @@ export class TooltipDirective implements OnChanges, OnDestroy, OnInit {
140153
this.listenersService.clearListeners();
141154
}
142155

156+
private intersectionServiceSubscribe(subscribe: boolean = true): void {
157+
if (subscribe) {
158+
this.intersectingSubscription = this.intersectionService.intersecting$
159+
.pipe(
160+
debounceTime(100)
161+
)
162+
.subscribe(isIntersecting => {
163+
this.visible = isIntersecting ? this.visible : false;
164+
!this.visible && this.removeTooltipElement();
165+
});
166+
} else {
167+
this.intersectingSubscription?.unsubscribe();
168+
}
169+
}
170+
143171
private getUID(prefix: string): string {
144172
let uid = prefix ?? 'random-id';
145173
do {

0 commit comments

Comments
 (0)