Skip to content

Commit 7084c99

Browse files
committed
fix(popover): add IntersectionObserver to remove popover when host element is not visible
1 parent 0f4ba8a commit 7084c99

File tree

2 files changed

+34
-4
lines changed

2 files changed

+34
-4
lines changed

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { ChangeDetectorRef, ElementRef, Renderer2, ViewContainerRef } from '@angular/core';
22
import { ListenersService } from '../services/listeners.service';
33
import { PopoverDirective } from './popover.directive';
4+
import { IntersectionService } from '../services';
45

56
describe('PopoverDirective', () => {
67
let document: Document;
@@ -11,7 +12,8 @@ describe('PopoverDirective', () => {
1112

1213
it('should create an instance', () => {
1314
const listenersService = new ListenersService(renderer);
14-
const directive = new PopoverDirective(document, renderer, hostElement, viewContainerRef, listenersService, changeDetectorRef);
15+
const intersectionService = new IntersectionService();
16+
const directive = new PopoverDirective(document, renderer, hostElement, viewContainerRef, listenersService, changeDetectorRef, intersectionService);
1517
expect(directive).toBeTruthy();
1618
});
1719
});

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

+31-3
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 { PopoverComponent } from './popover/popover.component';
2225
import { IListenersConfig, ListenersService } from '../services/listeners.service';
26+
import { IntersectionService } from '../services';
2327

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

3236
/**
3337
* Content of popover
@@ -92,15 +96,23 @@ export class PopoverDirective 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.addPopoverElement() : this.removePopoverElement();
@@ -110,6 +122,7 @@ export class PopoverDirective implements OnChanges, OnDestroy, OnInit {
110122
ngOnDestroy(): void {
111123
this.clearListeners();
112124
this.destroyPopoverElement();
125+
this.intersectionServiceSubscribe(false);
113126
}
114127

115128
ngOnInit(): void {
@@ -140,6 +153,21 @@ export class PopoverDirective 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.removePopoverElement();
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)