Reactive Programming with Angular by Example (Part 3)

Posted on Posted in Angular2

In the previous parts of this series, we’ve learned how to work with data loaded asynchronously. Now let’s have a look at some of the advanced use cases. How can we combine multiple REST calls if we need the result of both to start working?

Let’s continue our address example. Let’s assume we want to send a letter to a customer. To send the letter, we need two chunks of data: the content of the letter itself, and the address we want to print on the envelope. We can’t send the letter until we’ve received the response of both REST calls.

Merge and combineLatest

At first glance, merge() looks like the operator we’re looking for. It emits an array containing the latest values of two other Observables. But it’s too eager. It emits a value each time one of the merged Observables emits a value. Even if the only one of them has already fired, merge() emits a value.

combineLatest() is more useful. If doesn’t fire until each of Observables watched has emitted a value. So it’s a nice operator to “condense” two streams of data into a single stream consisting of pairs of the latest data.

ForkJoin

In the case of HTTP calls, using forkJoin() is probably a bit more appropriate. It fires if both streams have completed. In our case, that’s exactly what we need: REST calls are short-lived streams sending exactly one result, so forkJoin() waits until both REST calls have answered. When the second REST call sends it result, forkJoin() emits a single event consisting of a tuple containing both REST call responses.

That’s exactly what we need for our letter. We take both the address REST call and the letter content REST call, combine them to a joint stream and subscribe to it. The first (and only) event of the combined stream contains both the address and the content of the letter.

FlatMap

But wait – do we know which language to use? If the user comes from Italy, we’d like to send them a letter in Italian language. The REST call delivering the letter content take the language as a parameter. So we have to delay the second REST call until the first REST call has returned with an answer:

public getContent(): Observable<Observable<LetterContent>> {
   return http.get("https://example.com/rest/user/address")
      .map(response => {
        let url = "https://example.com/rest/letter/${response.language}"
        return http.get(url);
      });
}

This method returns an Observable wrapping another Observable. This isn’t exactly what we wanted to have. If it’s hard enough to deal with Observables to dedicate a series of articles to it, how hard is it to deal with Observables observing other Observables?

flatMap() to the rescue. This RX.js operator boils the two nested Observables down to a single one. It executes the outer REST call, passes the result to the inner REST call, executes the inner REST call and returns the result to the original caller.

Wait – why don’t we have all these problem in, say, JSF?

So far, we’ve learned in the series how to use RX.js to implement Angular applications calling REST calls asynchronously. We’ve also learned that it’s not that difficult to use RX.js. There are a few catches, and you’ll probably end in debugging hell once or twice, but you’ll master the art of asynchronous programming quickly.

Even so, I can’t help but wonder. In the good old times of JSF and JavaFX we never even had to think about calling things asynchronous. What has changed?

Well, our user’s have changed. And that includes us. If you’re like me, you get impatient after waiting a few second for a web application to respond. That’s the Google effect: Google’s search was one of the first application always delivering an answer in less than a second. Now everybody measures our applications by that standard.

SPAs, router and guards

But if you insist, you can implement your Angular application synchronously. Usually, the bulk of asynchronous REST calls occur when navigating to a new page. So, if you insist on programming “the old way”, you can use the resolve guard to make sure the data is available when you open the page.

Wrapping it up

As to my experience, working with asynchronous REST call needs some time to get used to it. However, it wasn’t really difficult until I noticed I need to use the result of multiple REST calls. But even that’s simple. Using the RX.js operators forkJoin and flatMap usually does the trick.

Dig deeper

RX.js combination operators
resolve guard

Leave a Reply

Your email address will not be published.