switchMapWithAsyncState The switchMapWithAsyncState operator combines the functionality of switchMap and createAsyncState into a single operator. It's tailor-made for scenarios where you need to trigger an API request based on user actions (like button clicks) and seamlessly transition between streams. By creating an AsyncState structure to encapsulate your API response, this operator delivers a seamless and efficient approach to managing asynchronous operations.
Examples Example 1: Filter Users by Gender Selecting a different gender will populate the user list accordingly:
Select gender to load users Male Female
import {switchMapWithAsyncState} from 'ngx-lift' ;
import {Component , inject} from '@angular/core' ;
import {FormControl , ReactiveFormsModule } from '@angular/forms' ;
import {ClarityModule } from '@clr/angular' ;
import {SpinnerComponent , AlertComponent } from 'clr-lift' ;
import {filter} from 'rxjs/operators' ;
import {AsyncPipe , NgIf , NgFor } from '@angular/common' ;
@Component ({
imports : [ReactiveFormsModule , ClarityModule , SpinnerComponent , AlertComponent , NgIf , NgFor , AsyncPipe ],
template : `
<clr-radio-container clrInline>
<label>Select Gender</label>
<clr-radio-wrapper>
<input type="radio" clrRadio name="gender" value="male" [formControl]="genderControl" />
<label>Male</label>
</clr-radio-wrapper>
<clr-radio-wrapper>
<input type="radio" clrRadio name="gender" value="female" [formControl]="genderControl" />
<label>Female</label>
</clr-radio-wrapper>
</clr-radio-container>
<div class="mt-6">
@if (searchState$ | async; as vm) {
@if (vm.isLoading) {
<cll-spinner />
}
@if (vm.error; as error) {
<cll-alert [error]="error" />
}
@if (vm.data; as users) {
<div class="card-grid">
@for (user of users; track user.id) {
<app-user-card [user]="user" />
}
</div>
}
}
</div>
`
})
export class FilterUsersComponent {
genderControl = new FormControl ('' );
private userService = inject (UserService );
searchState$ = this .genderControl .valueChanges .pipe (
filter (Boolean ),
switchMapWithAsyncState ((gender ) => this .userService .getUsers ({gender, results : 9 })),
);
}Example 2: Form Submission with Loading State Submit the form using switchMapWithAsyncState and toSignal. The submission will always emit an error because the API is designed to simulate an error.
import {switchMapWithAsyncState} from 'ngx-lift' ;
import {Component , inject} from '@angular/core' ;
import {toSignal} from '@angular/core/rxjs-interop' ;
import {HttpClient } from '@angular/common/http' ;
import {ClarityModule } from '@clr/angular' ;
import {AlertComponent } from 'clr-lift' ;
import {Subject } from 'rxjs' ;
@Component ({
imports : [ClarityModule , AlertComponent ],
template : `
<form>
<clr-input-container>
<label>Name</label>
<input clrInput name="username" />
</clr-input-container>
<button type="button" class="btn btn-primary" (click)="save()" [clrLoading]="saveAction()?.isLoading === true">
Save
</button>
@if (saveAction()?.error; as error) {
<cll-alert [error]="error" />
}
</form>
`
})
export class SubmitFormComponent {
private http = inject (HttpClient );
#saveAction = new Subject <void >();
saveAction = toSignal (
this .#saveAction.pipe (
switchMapWithAsyncState (() => {
return this .http .post ('https://randomuser.me/api' , {payload : 1 });
}),
),
);
save ( ) {
this .#saveAction.next ();
}
}API Reference switchMapWithAsyncState Combines switchMap and createAsyncState to transform an observable stream into AsyncState while switching to a new inner observable.
Signature switchMapWithAsyncState<T, R>(
project : (value : T, index : number ) => ObservableInput <R>
): OperatorFunction <T, AsyncState <R>>Parameters project: (value: T, index: number) => ObservableInput<R> A function that receives each value from the source observable and returns an Observable, Promise, or other ObservableInput.
Returns An observable that emits AsyncState<R> objects, automatically handling loading, error, and data states.