RxJs listen to scroll and take first emit of both directions

Viewed 293

I need to implement the morphing floating button functionality in my application.

I've created the needed CSS classes, and now I need to listen to element scroll to be able to apply some styles.

I've managed to implement this as follow and it works perfectly:

fromEvent(scrollableElement, 'scroll')
.pipe(untilDestroyed(this), debounceTime(100))
.subscribe(() => {
     const currentScrollPos = scrollableElement.scrollTop;

     buttonTextElement.classList.toggle('d-none', prevScrollPos < currentScrollPos);

     prevScrollPos = currentScrollPos;
});

Now I'm trying to improve this from a performance perspective and I was thinking about the following scenario:

  1. Listen to scroll
  2. Take only first emit of scroll down and skip the rest until scroll up
  3. Take only first emit of scroll up and skip the rest until scroll down
  4. Repeat

Is there a possibility to do this with RxJs operators?

1 Answers

You could try using distinctUntilChanged as shown below. The observable will emit either Up or Down and only when the direction is changed.

lastScrollTop: number = 0;

ngOnInit() {
  fromEvent(window, 'scroll')
    .pipe(
      untilDestroyed(this),
      debounceTime(100),
      map(() => {
        let st = window.pageYOffset || document.documentElement.scrollTop;
        let diff = st - this.lastScrollTop;
        this.lastScrollTop = st <= 0 ? 0 : st;
        return diff >= 0 ? 'Down' : 'Up';
      }),
      distinctUntilChanged()
    )
    .subscribe((scrollDirection) => {
      console.log('Scroll Direction:',scrollDirection);
    });
}
Related