I tried to make a HttpWrapper service to wrap the return object with a wrapper with loading value to load a spinner. At first, I initialize the Observable with loading: true
but it didn't work. The observable looks like null or undefined until get updated when API call is completed.
The wrapper service:
import { inject, Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { catchError, delay, map, Observable, of, switchMap } from 'rxjs';
export interface ApiResponse<T> {
data: T | null;
loading: boolean;
error?: Error | null;
}
@Injectable({
providedIn: 'root',
})
export class HttpWrapperService {
#httpClient = inject(HttpClient);
get<T>(url: string, params?: HttpParams): Observable<ApiResponse<T>> {
return of({ data: null, loading: true, error: null }).pipe(
delay(5000),
switchMap(() =>
this.#httpClient.get<T>(url, { params, withCredentials: true }).pipe(
map(
(data) => ({ data, loading: false, error: null } as ApiResponse<T>)
),
catchError((error) =>
of({ data: null, loading: false, error } as ApiResponse<T>)
)
)
)
);
}
}
The template:
<span>Loading: {{(dataObservable | async)?.loading}}</span>
#httpWrapper = inject(HttpWrapperService);
dataObservable: Observable<ApiResponse<any>> = of({
data: null,
loading: true,
error: null,
});
constructor() {
this.dataObservable = this.#httpWrapper.get(
'https://jsonplaceholder.typicode.com/todos/1'
);
}
I tried to init the dataObservable
with an Observable but it didn't work either. The loading value is undefined and change to false
when the call is finished.
Here is a simple repo:
https://stackblitz.com/edit/stackblitz-starters-4jyxfj5l?file=src%2Fmain.ts
You're close. You need to use startsWith
like below:
get<T>(url: string, params?: HttpParams): Observable<ApiResponse<T>> {
const initialVal = { data: null, loading: true, error: null };
return of(initialVal).pipe(
delay(5000),
switchMap(() => this.#httpClient.get<T>(url, { params, withCredentials: true }).pipe(
map(data => ({ data, loading: false, error: null } as ApiResponse<T>)),
catchError((error) => of({ data: null, loading: false, error } as ApiResponse<T>))
)),
startWith(initialVal)
);
}