Sitemap

Level Up Coding

Coding tutorials and news. The developer homepage gitconnected.com && skilled.dev && levelup.dev

RXJS

How To Use ForkJoin — Angular Example

ForkJoin is an RxJS operator commonly used to combine multiple Observables into a single Observable

4 min readFeb 2, 2023

--

Recently, I stumbled upon the need to combine a few Observables into a single stream that contained the result from each stream.

Specifically, in my case, I had to combine the outcome from several HTTP calls, that in Angular are Observables, into a single Observable.

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

Press enter or click to view image in full size
ForkJoin marble diagram
ForkJoin marble diagram

List of interesting things in this article

  • How To Use ForkJoin — Angular Example
  • A More Realistic Example & StackBlitz
  • Deprecated Syntax
  • Operator Decision Tree

What Is ForkJoin?

forkJoin is an RxJS operator that “Wait for Observables to complete and then combines [the] last values they emitted

In other words, forkJoinallows 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.

How To Use ForkJoin — Angular Example

If you are in a rush, here is a quick implementation.

However, I encourage you to read the explanation below or see a better implementation on StackBlitz.

...

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 Observable, 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.

We subscribe to the Observable and log the data in the console.

A More Realistic Example

What I showed above works well in the books but in real life, things tend to become a bit more complex.

A very common case involves the need to manipulate data and some error handling. We will take a look at them.

Manipulating Data

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

When using forkJoin we need to remember that the forkJoin operatorreturns an Observable that emits […] an array of values in the exact same order as the passed array”.

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

Get Lo Zarantonello’s stories in your inbox

Join Medium for free to get updates from this writer.

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

There are several error-handling strategies depending on the context and what you can do about it.

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 3rd party, or take some other action, such as logging the error.

Deprecated Syntax

Just a little warning.

In many examples, you will see syntax like the following.

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$})

Operator Decision Tree

If you don’t know the RxJS Operator Decision Tree, you should check it out. It will help you find or select the best operator for your needs.

Press enter or click to view image in full size
RxJS Operator Decision Tree
RxJS Operator Decision Tree

If you found this useful, show it!

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

Level Up Coding

Thanks for being a part of our community! Before you go:

🚀👉 Join the Level Up talent collective and find an amazing job

--

--

Level Up Coding
Level Up Coding
Lo Zarantonello
Lo Zarantonello

Written by Lo Zarantonello

Software Engineer | Instructor | Life Form Exploring His Surroundings

Responses (1)