Intersection observer in Angular

Viewed 5321

I am trying to set up IntersectionObserver in Angular but I can't get it to work. I want to load data when I scroll down using HttpClient from the server. I'm doing something like this: In HTML on the bottom of the page I have this:

<div #ob></div>

In the .ts file I am using ViewChild to grab the element and pass it to the IntersectionObserverService:

@ViewChild('ob') ob: ElementRef;

constructor(
    private inter: IntersectionObserverService) { }

 ngAfterViewInit(): void {
    this.inter.createAndObserve(this.ob);
  }

Then in the service I observe the passed in element and try to console.log the entries but nothing is happening.

@Injectable({
    providedIn: 'root'
})
export class IntersectionObserverService {
    _observer: IntersectionObserver | undefined;

    constructor() { }

    createAndObserve(element: ElementRef) {
        const options = {
            root: null,
            threshold: 0.1
        };

        this._observer = new IntersectionObserver((entries, observer) => {
            console.log('on')
            entries.forEach((entry: IntersectionObserverEntry) => {
                console.log(entry);
                console.log('okk');
                // observer.unobserve(entry.target);
            });
        }, options);
        this._observer.observe(element.nativeElement);
    }

}

I would want here to pass a callback to get my data from the backend when I intersect <div #ob></div>. Then pass it forward. How can I make the IntersectionObserver to observe it and display entries?

1 Answers

In your component do:

@ViewChild('ob', { read: ElementRef })
ob: ElementRef;

ngAfterViewInit(): void {
  this.inter.createAndObserve(this.ob).pipe(
    filter((isVisible: boolean) => isVisible),
    switchMap(() => this.yourService.loadData())
  ).subscribe(data => { ... });
}

Then go to your service and update your method, so now it will return an observable that will emit a boolean event everytime you intersect your host element:

createAndObserve(element: ElementRef): Observable<boolean> {
  return new Observable(observer => {
    const intersectionObserver = new IntersectionObserver(entries => {
      observer.next(entries);
    });

    intersectionObserver.observe(element.nativeElement);

    return () => { intersectionObserver.disconnect(); };
  }).pipe(
    mergeMap((entries: IntersectionObserverEntry[]) => entries),
    map(entry => entry.isIntersecting),
    distinctUntilChanged()
  );
}
Related