This lesson is for PRO members.

Unlock this lesson NOW!
Already subscribed? sign in

Sync Requests with RxJS and Angular

4:56 Angular 1.x lesson by

When you implement a search bar, the user can make several different queries in a row. With a Promise based implementation, the displayed result would be what the longest promise returns. Here we see how RxJs can be used to avoid this problem.

Get the Code Now
click to level up

egghead.io comment guidelines

Avatar
egghead.io

When you implement a search bar, the user can make several different queries in a row. With a Promise based implementation, the displayed result would be what the longest promise returns. Here we see how RxJs can be used to avoid this problem.

Avatar
Gadi

very cool.

Where is the module import for the Rx lib? I was expecting it in the angular.module( 'App', ['rx'] {})

PS. The JSBin code not working correctly, you get the previous results and it takes a long time to refresh.

In reply to egghead.io
Avatar
Joel

very cool.

Where is the module import for the Rx lib? I was expecting it in the angular.module( 'App', ['rx'] {})

PS. The JSBin code not working correctly, you get the previous results and it takes a long time to refresh.

Rx is a global library at window.Rx. Personally, I'd wrap Rx in a factory for injection for testability. It wouldn't be required though.

The responses are slow because the fakeService timeouts are 1.5 and 3 seconds. You can adjust that.

In reply to Gadi
Avatar
Christian Crowhurst

Is it possible / advisable to use RxJs 5 with AngularJS 1.5+?

I was thinking of trying to integrate RxJs with AngularJS but I though I would need to use a combination of RxJs 4 and the rx.angular.js bindings (https://github.com/Reactive-Extensions/rx.angular.js)

Whenever you create a search bar, you have to think about concurrent requests. In our example here, we have radio buttons, and each time you click one, they refresh the entities listed below. We have colors, furnitures, pets, and nothing.

The problem with the promise-based implementation is that you can't control the time a promise takes to resolve. Basically, if we click the foreigner here, you can see we end up within a very weird state where everything is out of sync.

This happens because we don't display the latest requests. We display the one which takes the longest time to resolve. This is a side effect of promises. We can't conceal them. The delay you observed is due to the timeouts, time I decided for each collection.

A first fix would be to use debounce in order to trigger requests whenever our radio buttons are clicked long enough, one after another. Let's give it a shot. Whenever I click allows and nothing now, because I did it within one second and a half. Only one request is made, and I can see the expected output.

The problem here is we have to assume a correct time. Too long, and the UI is not responsible enough, and too short, and we may encounter weirdness again.

I suggest here to use RxJS in order to solve our problem. In order to use it, we first have to create a source. A source is an observable, and it takes an observer as a param, and we are going to reuse the watch function we had before.

Instead of searching entities, we are going to pass the new value to the observer using the un-next function. Because we are only interested in the latest value, we are using flat map latest. It will take the type as param, and we can now use the promises we get from our data service and just convert them using Rx Observable.fromPromise.

We can remove the user's code now. Now we have our source. We can create a listener, so it's just a matter of source.subscribe. We are going to get the entities from it, so we only need to assign them to our controller.

Let's give it a shot. No matter what order we click the radio buttons, we'll always get the expected outcome. RxJS will handle that for us. The main benefit of RxJS over mere promises is we always get the latest query results. You can see, this implementation of Rx has a way to cancel promises.

I strongly encourage you to do two additional things now. The first thing is to clean after yourself. On each destroy event on the scope, so basically, whenever you use a router, it could be on route change, you have to dispose the listener so Rx knows it can get rid of everything linked to it.

The second thing is we don't want to put too much pressure on our server, so we are going to use debounce again. It's very important to understand here that debounce is not a way to avoid UI issues. It's a way to avoid useless server queries.

HEY, QUICK QUESTION!
Joel's Head
Why are we asking?