I have a service that exposes some global state using an observable. The state must be initialized by making an HTTP call. I want all consumers of the state to receive the same value, receive the current value when they subscribe to the observable, and receive updates when the state changes.
This scenario is typically handled using a Subject, which can be initialized by subscribing it to the observable returned by the HTTP request.
However, I don't want the HTTP request to be executed until the first time something subscribes to the global state observable. If you use the subscribe method of the Subject, the HTTP request is called then.
I have the following code in the service. This works, but it seems like there should be a simpler way to do this.
private initialized = false;
private readonly subject = new ReplaySubject<string>(1);
constructor(private readonly httpClient: HttpClient) {}
get data$(): Observable<string> {
return new Observable<string>(subscriber => {
if (!this.initialized) {
this.refresh();
}
let subscription = this.subject.subscribe(value => subscriber.next(value));
return () => subscription.unsubscribe();
});
}
refresh(): void {
this.httpClient.get<string>('https://...')
.pipe(
tap(() => this.initialized = true)
)
.subscribe(value => this.subject.next(value));
}
Sandbox: https://codesandbox.io/s/reverent-almeida-d2zbjx?file=/src/app/test.service.ts