Skip to content

Commit

Permalink
feat(rx): add rx-observe-intersection directive
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelbe812 committed Jan 17, 2023
1 parent 03e7c02 commit b767c4e
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,59 @@
import {ObserveIntersectionDirective} from './observe-intersection.directive';
import {RxObserveIntersectionDirective, RxObserveIntersectionDirectiveModule} from './observe-intersection.directive';
import {Component, ViewChild} from "@angular/core";
import {ComponentFixture, fakeAsync, TestBed, tick} from "@angular/core/testing";
import {mockIntersectionObserver} from '@angular-kit/test-helpers';
import {subscribeSpyTo} from "@hirez_io/observer-spy";

describe('ObserveIntersectionDirective', () => {
it('should create an instance', () => {
const directive = new ObserveIntersectionDirective();
expect(directive).toBeTruthy();
it('should create an instance', async () => {
const { testComponent } = await create();
expect(testComponent).toBeTruthy();
});

it('should emit on intersection', fakeAsync (async () => {
const {testComponent, fixture} = await create();
const result = subscribeSpyTo(testComponent.directive.intersect);

fixture.nativeElement.dispatchEvent(new Event('intersect'));
tick(1000)
expect(result.getValues().length).toEqual(1)
}));
});


async function create() {
@Component({
template: `
<section style="position: relative; height: 200px; overflow: auto;">
<h1
id="resize_elem"
style="position: absolute; top: 200px; height: 200px;"
rxObserveIntersection
(intersect)="onChange()"
>
I'm being observed
</h1>
</section>
`,
})
class TestComponent {
@ViewChild(RxObserveIntersectionDirective, {static: true}) directive!: RxObserveIntersectionDirective;
onChange = jest.fn();
observe = true;
}

let fixture: ComponentFixture<TestComponent>;
let testComponent: TestComponent;

TestBed.configureTestingModule({
imports: [RxObserveIntersectionDirectiveModule],
declarations: [TestComponent],
});
mockIntersectionObserver();
fixture = TestBed.createComponent(TestComponent);
testComponent = fixture.componentInstance;
fixture.detectChanges();

return { fixture, testComponent };
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,75 @@
import {Directive, NgModule} from '@angular/core';
import {Directive, ElementRef, EventEmitter, Input, NgModule, OnDestroy, Output} from '@angular/core';
import {CommonModule} from '@angular/common';
import {combineLatest, mergeMap, SchedulerLike, startWith, Subscription} from 'rxjs';
import {createIntersectionObserver} from '../create-intersection-observer';
import {createSignal} from '@angular-kit/rx/signal';

@Directive({
selector: '[rxObserveIntersection]',
})
export class ObserveIntersectionDirective {
// todo
// siehe angular-collection
// evtl auch inview directive portieren
constructor() {}
export class RxObserveIntersectionDirective implements OnDestroy {
private sub = new Subscription();
private rxObserveIntersectionDebounceSignal = createSignal<number>(0);
private rxObserveIntersectionRootMarginSignal = createSignal<string>('0px');
private rxObserveIntersectionRootSignal = createSignal<HTMLElement | undefined>(undefined);
private rxObserveIntersectionThresholdSignal = createSignal<number | number[]>(0);
private rxObserveIntersectionSchedulerSignal = createSignal<SchedulerLike | undefined>(undefined);

@Input() set rxObserveIntersectionDebounce(debounceInMs: number) {
this.rxObserveIntersectionDebounceSignal.send(debounceInMs);
}
@Input() set rxObserveIntersectionRootMargin(rootMargin: string) {
this.rxObserveIntersectionRootMarginSignal.send(rootMargin);
}
@Input() set rxObserveIntersectionRoot(root: HTMLElement | undefined) {
this.rxObserveIntersectionRootSignal.send(root);
}
@Input() set rxObserveIntersectionThreshold(threshold: number | number[]) {
this.rxObserveIntersectionThresholdSignal.send(threshold);
}
@Input() set rxObserveIntersectionScheduler(scheduler: SchedulerLike) {
this.rxObserveIntersectionSchedulerSignal.send(scheduler);
}

@Output() intersect = new EventEmitter<IntersectionObserverEntry[]>();

constructor(private element: ElementRef) {
this.sub = combineLatest([
this.rxObserveIntersectionDebounceSignal.$.pipe(startWith(0)),
this.rxObserveIntersectionRootMarginSignal.$.pipe(startWith('0px')),
this.rxObserveIntersectionRootSignal.$.pipe(startWith(undefined)),
this.rxObserveIntersectionThresholdSignal.$.pipe(startWith(0)),
this.rxObserveIntersectionSchedulerSignal.$.pipe(startWith(undefined)),
])
.pipe(
mergeMap(([debounce, rootMargin, root, threshold, scheduler]) =>
createIntersectionObserver(
this.element,
{
root: root,
rootMargin: rootMargin,
threshold: threshold,
},
{
throttleMs: debounce,
scheduler: scheduler,
}
)
)
)
.subscribe((entries) => {
this.intersect.emit(entries);
});
}

ngOnDestroy(): void {
this.sub.unsubscribe();
}
}

@NgModule({
imports: [CommonModule],
declarations: [ObserveIntersectionDirective],
exports: [ObserveIntersectionDirective],
declarations: [RxObserveIntersectionDirective],
exports: [RxObserveIntersectionDirective],
})
export class ObserveIntersectionDirectiveModule {}
export class RxObserveIntersectionDirectiveModule {}

0 comments on commit b767c4e

Please sign in to comment.