switchMapWithAsyncState
Frequently, we find ourselves in situations where triggering an API request upon a user's button click is essential. But how do we seamlessly transition between streams? Enter the solution: switchMapWithAsyncState
. This operator is tailor-made for such scenarios, effortlessly amalgamating the strengths of both the switchMap
and createAsyncState
operators. By creating an AsyncState
structure to encapsulate your API response, this operator becomes a versatile powerhouse, delivering the combined functionalities of switchMap
and createAsyncState
in one. The result is a seamless and efficient approach to managing asynchronous operations.
Example 1
Selecting a different gender will populate the user list accordingly.
import {switchMapWithAsyncState} from 'ngx-lift';
// ... other imports
@Component({
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" *ngIf="searchState$ | async as vm">
<cll-spinner *ngIf="vm.loading" />
<cll-alert *ngIf="vm.error as error" [error]="error" />
<div *ngIf="vm.data as users" class="card-grid">
<app-user-card *ngFor="let user of users" [user]="user" />
</div>
</div>
`
})
export class FilterUsersComponent {
genderControl = new FormControl('');
searchState$ = this.genderControl.valueChanges.pipe(
filter(Boolean),
switchMapWithAsyncState((gender) => this.userService.getUsers({gender, results: 9})),
);
private userService = inject(UserService);
}
Example 2
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 {toSignal} from '@angular/core/rxjs-interop';
@Component({
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()?.loading === 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();
}
}