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
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
[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.[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.[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 .[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[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 completedLink 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,
getQuotesAPI
— returns the api url with the current page number as query paramprocessData
— processes the return data from the api which is performed using fetch API and increase the currentPage.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
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