I recently stumbled upon the need to combine a few Observables into a single stream that contained the result from each stream. I had to combine the outcome from several HTTP calls that are called Observables in Angular into a single Observable.

ForkJoin Definition

In Angular, forkJoin is an operator that allows you to wait for multiple observables to complete and then emits their latest values as an array. It allows you to combine the results of multiple HTTP requests. 

After some tinkering, I came to the conclusion that forkJoin was the right tool for the job.

forkJoin is an RxJS operator that allows you to wait for multiple Observables to complete and then emits their latest value as an array.

Here’s what we’ll cover in this article:

  1. How to use forkJoin in Angular.
  2. Realistic examples of forkJoin.
  3. Basic error handling in forkJoin.
  4. What an operator decision tree is.

 

What Is ForkJoin?

 As we noted earlier, forkJoin allows you to wait for multiple Observables to complete and then emit their latest values as an array.

It can be used to combine the results of multiple HTTP requests, for example, and emit the results only when all of them are complete.

More on Software EngineeringCan Google’s Carbon Language Replace C++?

 

How To Use ForkJoin in Angular 

Here is a quick implementation of forkJoin.

...

export class App implements OnInit {
  sources = [
    this.http.get('https://jsonplaceholder.typicode.com/users/1'),
    this.http.get('https://jsonplaceholder.typicode.com/users/2'),
    this.http.get('https://jsonplaceholder.typicode.com/users/3'),
  ];

  constructor(private http: HttpClient) {}

  ngOnInit() {
    forkJoin(this.sources).subscribe(console.log);
  }
}

The sources array contains three Observables created by three HTTP calls that use the http Angular service. The forkJoin operator takes an array of Observables, so we pass in the sources array.

When the array is passed into forkJoin, the operator waits for each Observable (HTTP call) to complete. Then, it combines the last value from each call into a single Observable.

Then you subscribe to the Observable and log the data in the console.

 

Example of ForkJoin in Angular

What I showed above works well in theory, but in real life, things tend to be a bit more complicated.

A very common case involves the need to manipulate data and handle some errors. We’ll take a look at a few examples, which you can review in Stackblitz. Once Stackblitz installs all packages, you might need to refresh the view to see the example in the console.

 

Manipulating Data With Forkjoin

Most of the time, the back end returns data that has to be manipulated  by the front end.

When using forkJoin, we need to remember that the forkJoin operator “returns an Observable that emits […] an array of values in the exact same order as the passed array,” according to the RxJS documentation.

Expanding our example, we can use the map operator to transform the emitted values.

The map operator takes as input the array containing the latest values emitted by the three Observables that were passed to forkJoin, and returns a new object with three properties, userOne, userTwo and userThree, that correspond to the latest values emitted by each of the three Observables.

forkJoin(this.sources)
      .pipe(
        map(([userOne, userTwo, userThree]) => {
          return {
            userOne: userOne,
            userTwo: userTwo,
            userThree: userThree,
          };
        })
      )
      .subscribe(console.log);

The extensive syntax reported above can be simplified as follows:

  1. Removing the return keyword when the returned object starts on the same line as the function.
  2. Don’t repeat the assignment in the object if the value has the same name as the key.
  forkJoin(this.sources)
      .pipe(
        map(([userOne, userTwo, userThree]) => ({
          userOne,
          userTwo,
          userThree,
        }))
      )
      .subscribe(console.log);

Finally, we can manipulate data in the map operator by using object restructuring and updating the values.

map(([userOne, userTwo, userThree]) => ({
  userOne: { ...userOne, name: 'Lorenzo' },
  userTwo,
  userThree,
}))

 

Basic Error Handling With ForkJoin

There are several error-handling strategies that depend on the context.

However, they all capitalize on the catchError operator that catches errors in the source Observable and handles them appropriately by returning a new Observable or throwing an error.

The following example expands the code so that, should an error occur, the catchError operator would catch it and return a new Observable.

forkJoin(this.sources)
  .pipe(
    map(([userOne, userTwo, userThree]) => ({
      userOne: { ...userOne, name: 'Lorenzo' },
      userTwo,
      userThree,
    })),
    catchError((error) => of({ error }))
  )

The of operator is only a placeholder. You can use the emitted error value to inform the user, send the error to a server or a third party, or take some other action, such as logging the error.

 

Deprecated Syntax

forkJoin(
  this.http.get<User>('https://jsonplaceholder.typicode.com/users/1'),
  this.http.get<User>('https://jsonplaceholder.typicode.com/users/2'),
  this.http.get<User>('https://jsonplaceholder.typicode.com/users/3')
)

This syntax is deprecated. As reported in the documentation, passing Observables directly as parameters is deprecated. This is called rest-parameter signature and it will be removed in RxJS v8.

RxJS suggests passing an array of sources, as we did in the examples above.

// From RxJS

// deprecated
forkJoin(odd$, even$);
// suggested change
forkJoin([odd$, even$]);
// or
forkJoin({odd: odd$, even: even$})
A tutorial on how to use forkJoin in Angular. | Video: Sourav

More on Software EngineeringA Guide to Using ggmap in R

 

What Is an Operator Decision Tree?

You should familiarize yourself with the RxJS Operator Decision Tree. It will help you find or select the best operator for your needs.

screenshot of the RxJS operator decision tree
Screenshot of the RxJS operator decision tree. | Image: Lorenzo Zarantonello

And if you find RxJS annoying, Angular signals might be your way out, at least in the beginning

Expert Contributors

Built In’s expert contributor network publishes thoughtful, solutions-oriented stories written by innovative tech professionals. It is the tech industry’s definitive destination for sharing compelling, first-person accounts of problem-solving on the road to innovation.

Learn More

Great Companies Need Great People. That's Where We Come In.

Recruit With Us