combineLatestEager
The RxJS operator combineLatest
is frequently employed to merge multiple observables, triggering emissions whenever any of the source observables emits a value. However, a limitation arises as it mandates all sources to emit at least once. In UI scenarios, combineLatest
is often employed to construct a view model observable (vm$
). When one of the sources is a Subject
, using vm$
with the async pipe becomes problematic because the Subject
may not emit any values initially. This issue is elegantly addressed by the augmented functionality of the combineLatestEager
function.
combineLatestEager
seamlessly extends the capabilities of combineLatest
by incorporating startWith(null)
for each Subject
present in the provided sources. This augmentation ensures that the combined observable initializes with a null value for each Subject
, resolving the challenge posed by combineLatest
in scenarios where initial emissions from certain sources are not guaranteed.
In most cases, the aforementioned approach should work seamlessly for you. However, when dealing with numerous observables, it might become challenging to distinguish which ones lack initial emissions. For such scenarios, you have the flexibility to set the second parameter to true in combineLatestEager, which appends startWith(null)
for all source observables. This option becomes especially valuable when dealing with situations where ensuring initial emissions is crucial.
Example Code
@if (vm$ | async; as vm) {
<p>
Today is <time> {{ vm.today | date }} </time>. Who is our today's rock star?
<button (click)="showRockStar()" class="btn btn-outline">Unveil</button>
</p>
@if (vm.rockStarState?.error; as error) {
<cll-alert [error]="error" />
}
@if (vm.rockStarState?.loading) {
<cll-spinner />
}
@if (vm.rockStarState?.data; as rockStar) {
<p class="!text-xl">{{ rockStar.name }}</p>
}
}
import {AlertComponent, SpinnerComponent} from 'clr-lift';
import {combineLatestEager, switchMapWithAsyncState} from 'ngx-lift';
import {of, Subject} from 'rxjs';
export class RockStarComponent {
today$ = of(new Date());
private showStarAction = new Subject<void>();
private http = inject(HttpClient);
rockStarState$ = this.showStarAction.pipe(
switchMapWithAsyncState(() => this.http.get<{name: string}>('https://jsonplaceholder.typicode.com/users/1')),
);
// using RxJS combineLatest won't work because showStarAction won't emit initial value until button click
vm$ = combineLatestEager({today: this.today$, rockStarState: this.rockStarState$});
showRockStar() {
this.showStarAction.next();
}
}
Today is . Who is our today's rock star?