Skip to content

Commit 86fcf51

Browse files
committed
feat(rx): create rxRenderInViewPort directive
1 parent 95176f4 commit 86fcf51

File tree

5 files changed

+104
-157
lines changed

5 files changed

+104
-157
lines changed

libs/rx/platform/src/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,4 @@ export * from './lib/create-mutation-observer';
44

55
export * from './lib/directives/rx-observe-resize.directive';
66
export * from './lib/directives/observe-intersection.directive';
7-
8-
export * from './lib/directives/rx-observe-visibility.directive';
7+
export * from './lib/directives/observe-intersection.directive';

libs/rx/platform/src/lib/directives/in-view.directive.spec.ts

Lines changed: 0 additions & 4 deletions
This file was deleted.

libs/rx/platform/src/lib/directives/in-view.directive.ts

Lines changed: 0 additions & 151 deletions
This file was deleted.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// todo
2+
describe('RxRenderInViewDirective', () => {
3+
4+
});
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import {
2+
AfterViewInit,
3+
Directive,
4+
EmbeddedViewRef,
5+
Input,
6+
NgModule,
7+
OnDestroy,
8+
TemplateRef,
9+
ViewContainerRef,
10+
} from '@angular/core';
11+
import {CommonModule} from '@angular/common';
12+
import {combineLatest, mergeMap, SchedulerLike, startWith, Subscription} from 'rxjs';
13+
import {createSignal} from '../../../../signal/src';
14+
import {createIntersectionObserver} from '../create-intersection-observer';
15+
16+
@Directive({
17+
selector: '[rxRenderInViewport]',
18+
})
19+
export class RxRenderInViewportDirective implements AfterViewInit, OnDestroy {
20+
private alreadyRendered = false; // cheking if visible already
21+
private embeddedViewRef: EmbeddedViewRef<unknown> | null = null;
22+
private sub = new Subscription();
23+
24+
private rxObserveVisibilityDebounceSignal = createSignal(0);
25+
private rxObserveVisibilityRootMarginSignal = createSignal('0px');
26+
private rxObserveVisibilityRootSignal = createSignal<HTMLElement | undefined>(undefined);
27+
private rxObserveVisibilityThresholdSignal = createSignal<number | number[]>(0);
28+
private rxObserveVisibilitySchedulerSignal = createSignal<SchedulerLike | undefined>(undefined);
29+
30+
@Input() set rxRenderInViewport(rootMargin: string) {
31+
this.rxObserveVisibilityRootMarginSignal.send(rootMargin);
32+
}
33+
@Input() set rxRenderInViewportDebounce(debounceInMs: number) {
34+
this.rxObserveVisibilityDebounceSignal.send(debounceInMs);
35+
}
36+
@Input() set rxRenderInViewportRoot(root: HTMLElement | undefined) {
37+
this.rxObserveVisibilityRootSignal.send(root);
38+
}
39+
@Input() set rxRenderInViewportThreshold(threshold: number | number[]) {
40+
this.rxObserveVisibilityThresholdSignal.send(threshold);
41+
}
42+
@Input() set rxRenderInViewportScheduler(scheduler: SchedulerLike) {
43+
this.rxObserveVisibilitySchedulerSignal.send(scheduler);
44+
}
45+
46+
constructor(private vcRef: ViewContainerRef, private tplRef: TemplateRef<unknown>) {}
47+
48+
ngAfterViewInit() {
49+
this.sub = combineLatest([
50+
this.rxObserveVisibilityDebounceSignal.$.pipe(startWith(0)),
51+
this.rxObserveVisibilityRootMarginSignal.$.pipe(startWith('0px')),
52+
this.rxObserveVisibilityRootSignal.$.pipe(startWith(undefined)),
53+
this.rxObserveVisibilityThresholdSignal.$.pipe(startWith(0)),
54+
this.rxObserveVisibilitySchedulerSignal.$.pipe(startWith(undefined)),
55+
])
56+
.pipe(
57+
mergeMap(([debounceInMs, rootMargin, root, threshold, scheduler]) =>
58+
createIntersectionObserver(
59+
this.vcRef.element.nativeElement.parentElement,
60+
{
61+
root: root,
62+
rootMargin: rootMargin,
63+
threshold: threshold,
64+
},
65+
{
66+
throttleMs: debounceInMs,
67+
scheduler: scheduler,
68+
}
69+
)
70+
)
71+
)
72+
.subscribe((entries) => {
73+
const entry = entries[0];
74+
this.renderContents(entry.isIntersecting);
75+
});
76+
}
77+
78+
ngOnDestroy() {
79+
this.embeddedViewRef?.destroy();
80+
this.vcRef?.clear();
81+
this.sub.unsubscribe();
82+
}
83+
84+
renderContents(isInView: boolean) {
85+
if (isInView && !this.alreadyRendered) {
86+
this.vcRef.clear();
87+
this.embeddedViewRef = this.vcRef.createEmbeddedView(this.tplRef);
88+
this.embeddedViewRef.detectChanges();
89+
this.alreadyRendered = true;
90+
}
91+
}
92+
}
93+
94+
@NgModule({
95+
imports: [CommonModule],
96+
declarations: [RxRenderInViewportDirective],
97+
exports: [RxRenderInViewportDirective],
98+
})
99+
export class RxRenderInViewportDirectiveModule {}

0 commit comments

Comments
 (0)