Reputation: 1863
I have a CRUD API where the get on the entity returns both the list and the total number of items for the current filter configuration.
For example : GET /posts
{
"items": [
{
"id": 1,
"title": "post title 1"
}
...
],
"total": 9
}
How can I create an observable where the HTTP query is executed only one time but where I can subscribe to either the total value or the items list ?
I am in an Angular2 context with typescript.
I first tried this and it worked :
this.http.get('/api/posts').map(response => response.json()).subscribe(data => {
var items = data.items
var total = data.total
});
But I don't like this as I cannot use my interface for the Post entity (or I must defined an interface like that {items: Post, total: number}
this is not really graceful). What I would like to do is something like this :
this.myPostService.totalObservable.subscribe(total => this.total = total)
this.myPostService.itemsObservable.subscribe(items => this.items = items)
But without triggering 2 queries.
I looked into this blog post : https://coryrylan.com/blog/angular-2-observable-data-services but I don't like the fact that you first subscribe and then call the list() method to load the list.
Upvotes: 1
Views: 1289
Reputation: 18663
If you only need it to run once you can cache the value directly:
var source = this.http.get('/api/posts').map(response => response.json()).publishLast();
//unsubscribe from this when you are done
var subscription = source.connect();
Then you can expose the two sources as:
var totalObservable = source.pluck('total');
var itemsObservable = source.pluck('items');
If on the other hand you need to call these Observables multiple times, then I would recommend that you wrap the get
in a triggering Observable and cache:
var source = sourceTrigger
.startWith(0) //Optionally initialize with a starting value
//This ensures that only the latest event is in flight.
.flatMapLatest(() => this.http.get('/api/posts'), (_, resp) => resp.json())
.cache(1);
//Again expose these items using `pluck`
var totalObservable = source.pluck('total');
var itemsObservable = source.pluck('items');
In the second case the sourceTrigger
would be an Observable
that might be connected to a button event, so that each button click triggers a new request.
Upvotes: 3