Naive Infinite scroll in Reactive Programming using RxJS Observables

Written by Sureshkumar_Ash | Published 2017/02/09
Tech Story Tags: javascript | rxjs | reactive-programming

TLDRvia the TL;DR App

A simple experiment to implement infinite scroll with RxJS

Blog post on Angular Implementation : Simple Infinite Scroller directive with RxJS Observables

**What is Reactive Programming ?**In simple terms it is programming with asynchronous data streams. There is a great post by Andre Staltz — The introduction to Reactive Programming you’ve been missing accompanied by an egghead.io video.

The introduction to Reactive Programming you’ve been missing

https://egghead.io/courses/introduction-to-reactive-programming

What is RxJS?

RxJS or Reactive Extensions is a library developed by Microsoft Open Technologies in Javascript for transforming, composing and querying data streams. https://github.com/Reactive-Extensions/RxJS

There is a great talk by Ben Lesh on this Thinking Reactively with RxJS 5

Below are a couple of nice introductions to Observables and a few operators by Netanel Basal

  1. Observables under the hood.
  2. RxJS — Six Operators That you Must Know

What will we be building?

We are going to build a naive infinite scroller using observables. Whenever the user scrolls a given container to 70%, we will trigger the api call to get more data from the server. For this implementation we will use the HackerNews unofficial api to get the latest news.

Below are the operators we will be using from RxJS

  1. [map](http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-map) : similar to map in an array, map over the stream of incoming data.
  2. [filter](http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-filter) : similar to filter in an array, filter the stream of incoming data.
  3. [pairwise](http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-pairwise) : returns an array of current emitted data and also the previous emitted data .
  4. [startWith](http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-startWith) : returns an observable emits supplied values before emitting the values from source observable
  5. [exhaustMap](http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-exhaustMap) : waits to emit value until the passed in inner observable has completed

Link to the output in jsbin.com : https://output.jsbin.com/punibux

#Phase1 — Setup basic html and styles

Import the RxJS library and we will use infinite-scroller as a scroll container and append news to it.

#Phase2 — Setup helpers functions for data processing, rendering and calculations

First three functions are straight forward,

  1. getQuotesAPI — returns the api url with the current page number as query param
  2. processData — processes the return data from the api which is performed using fetch API and increase the currentPage.
  3. renderNews — takes each news item and renders to the view.

The next two functions are the ones used for scroll calculations

4. isUserScrollingDown — determines if the user is scrolling down or not.

5. isScrollExpectedPercent — determines if the user has scrolled to the passed in percentage to get more data.

#Phase3 — Setup up observable stream

To capture the scroll events in the container, we need to create an observable from the scroll event. This can be achieved by using Rx.Observable.fromEvent- docs. It is a convention to append $ to the variable when referencing an observable stream.

#Phase4 — Stream logic to process scroll events and call the api

We are going to take the scroll event emitted by scrollEvent$ and map over to take only the values we need for our infinite scroll logic. We need only three properties from the scroll element — [scrollHeight](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight), [scrollTop](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollTop) and [clientHeight](https://developer.mozilla.org/en-US/docs/Web/API/Element/clientHeight).

We pass the mapped data to pairwise operator which emits the current and previous value in an array which will look like below.

Now we can take the pair of positions and pass it to the filter them to filter according to our conditions

  1. Is the user scrolling down
  2. Has the user scrolled reached seventy percent of the container

requestOnScroll$ — It gets invoked when the userScrollDown$ has passed filter conditions. We start with an initial value of an empty array.

We going to use [Rx.Observable.fromPromise](http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#static-method-fromPromise) to create an observable from a promise. fetch makes the http call and returns a promise. exhaustMap will wait for the fetch to complete and the inner observable to emit the data from the API.

Observables are lazy — means they do not do anything until you subscribe to them. We will subscribe to the requestOnScroll$ and pass in processData to the subscribe method. When exhaustMap emits the data from the api it will be passed on to processData which will call renderNews to render on to the view.

Below is the gif of the infinite scroll in action, watch the scroll bar on the right.

In my next post I will try to implement it in Angular 2 by creating an infinite scroll directive.

Update: Here is the link to my follow post on Simple Infinite Scroller directive with RxJS Observables


Published by HackerNoon on 2017/02/09