In this tutorial, we’re going to explore the combineLatest
operator in Angular and how it can be used to combine the latest values from multiple observables.
We’ll cover the basics of combineLatest
and then we will see how to use it through an example, then we will discover the difference between combineLatest
and forkJoin
operators.
By the end of this tutorial, you’ll have a solid understanding of how to use combineLatest
operator to build powerful reactive applications with Angular and RxJS.
Understanding the basics of the combineLatest operator
The combineLatest
operator is an example of a combination operator in RxJS. It takes one or more observables as arguments and returns a new observable.
Whenever any of the source observables emit a new value, combineLatest
emits a new value that is the result of combining the latest emitted values from all the source observables.
Here’s an example of using combineLatest
in Angular:
import { combineLatest, Observable } from 'rxjs';
// define two observables to combine
const source1$: Observable = ...
const source2$: Observable = ...
// combine the observables using combineLatest
const combined$ = combineLatest([source1$, source2$]);
// subscribe to the combined observable
combined$.subscribe(([num, str]) => {
console.log(`Latest values: ${num} and ${str}`);
});
In this example, we define two observables, source1$
and source2$
, and combine them using combineLatest
.
The resulting combined$
observable emits an array of the latest values from both source observables whenever either of them emits a new value.
How to use the combineLatest operator with examples
Suppose we have a form with two input fields, one for a name
and one for an email address
.
We want to combine the values of these fields into a single object and perform some action whenever the user updates either field (name or email). We can use combineLatest
to accomplish this:
import { combineLatest, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { FormGroup, FormControl } from '@angular/forms';
// define a reactive form
const form = new FormGroup({
name: new FormControl(''),
email: new FormControl('')
});
// create an observable that emits form values
const formValues$ = combineLatest([
form.get('name').valueChanges,
form.get('email').valueChanges
]).pipe(
map(([name, email]) => ({ name, email }))
);
// subscribe to the form values observable
formValues$.subscribe(values => {
console.log('Form values:', values);
});
In this example, we create a reactive form using Angular’s FormGroup
and FormControl
classes.
We then create an observable formValues$
that emits an object with the latest values of both form fields whenever either of them changes.
differences between combineLatest and forkJoin
Although combineLatest
and forkJoin
are both operators that can be used to combine multiple observables, there are some key differences in their behaviour and use cases.
In this section, we will explore these differences by comparing the behaviour of combineLatest
and forkJoin using a real life example.
Suppose we need to fetch data from two different APIs with different time response and combine the results into a single data structure (using two operators)
using combineLatest operator:
In this example, we’re using combineLatest
to combine the results of two API calls.
The first API call returns immediately and emits { data1: 'Hello' }
after a delay of 1 second.
The second API call has a delay of 5 seconds and emits { data2: 'World' }
after that delay.
import { combineLatest, of } from 'rxjs';
import { delay } from 'rxjs/operators';
const api1 = of({ data1: 'Hello' }).pipe(delay(1000));
const api2 = of({ data2: 'World' }).pipe(delay(5000));
combineLatest([api1, api2]).subscribe(([result1, result2]) => {
console.log('Combined Result:', { ...result1, ...result2 });
});
// Output after 1 second:
// Combined Result: { data1: 'Hello', data2: undefined }
// Output after 5 seconds:
// Combined Result: { data1: 'Hello', data2: 'World' }
When we subscribe to the combineLatest
observable, Initially, we only have { data1: 'Hello', data2: undefined }
because the second API call hasn’t completed yet.
However, after the second API call completes, we get { data1: 'Hello', data2: 'World' }
using forkJoin operator:
In this example, we’re using forkJoin operator to combine the results of the two API calls (of the previous example)
import { forkJoin, of } from 'rxjs';
import { delay } from 'rxjs/operators';
const api1 = of({ data1: 'Hello' }).pipe(delay(1000));
const api2 = of({ data2: 'World' }).pipe(delay(5000));
forkJoin([api1, api2]).subscribe(([result1, result2]) => {
console.log('Combined Result:', { ...result1, ...result2 });
});
// Output after 5 seconds:
// Combined Result: { data1: 'Hello', data2: 'World' }
When we subscribe to the forkJoin
observable, forkJoin
waits for all observables to complete before emitting a value, we don’t get any results until the second API call completes, and then we get { data1: 'Hello', data2: 'World' }
.
Check this tutorial if you want to read more aboutforkJoin operator
As you see, combineLatest
operator is useful when we want to combine the latest values of multiple observables and issue new values when any source observable issues a new value.
On the other hand, forkJoin operator is useful when we want to wait for all source observables to complete and issue a single value that combines the results of all observables.