A classic task when you have some input field and you have to fetch something on values changes. Let's imagine we use Angular Reactive Forms. Example:
orders$ = inputControl.valueChanges.pipe(
switchMap((value) => {
return someService.fetch(value);
})
);
Now we should also somehow manage loading state. I usually use tap
:
orders$ = inputControl.valueChanges.pipe(
tap(() => { loading = true }), // or loading$.next(true) if loading is a subject
switchMap((value) => {
return someService.fetch(value);
}),
tap(() => { loading = false }), // or loading$.next(false) if loading is a subject
);
However it seems we can somehow avoid assigning values in the tap
and use RxJs instead.
But I could not find a way to do with it.
For me, the usage of the ideal solution would be
orders$ = <some abstraction here that depends on inputControl.valueChanges and fetching>
loading$ = <some abstraction here that depends on fetching>
CodePudding user response:
You can use the map and shareReplay operators to achieve this. The map operator can be used to return the value from the service call and the shareReplay operator can be used to share the observable and keep the loading state.
orders$ = inputControl.valueChanges.pipe(
switchMap((value) => {
return someService.fetch(value).pipe(
map(data => {
loading$.next(false);
return data;
}),
startWith({loading: true})
);
}),
shareReplay(1)
);
loading$ = orders$.pipe(map(data => data.loading));
This way you can use the orders$ observable to subscribe to the orders and loading$ observable to subscribe to the loading state. Note : The above example will not work if you return a object from service call, you would need to wrap the object in another object with loading property like {data: {}, loading: true/false}
CodePudding user response:
Take a look at my library ez-state.
https://github.com/adriandavidbrand/ngx-ez/tree/master/projects/ez-state
orderCache = new EzCache<Order[]>();
order$ = this.orderCache.value$;
loading$ = this.orderCache.loading$;
inputControl.valueChanges.subscribe(value => {
orderCache.load(someService.fetch(value));
});
An EzCache is a glorified behaviour subject that has methods load, save, update and delete and manages state observables like loading$, loaded$, saving$, saved$ etc.
I would personally would have the cache in the service and expose the observables from the service like in that article I wrote.