1

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.

1
  • Hi @paulpdaniels. I have updated my question with some examples. Commented May 13, 2016 at 18:05

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Your second solution was exactly what I was looking for. Thanks. I didn't know the pluck method and couldn't find it in the doc.
I had to use share on the source to prevent the queries being emitted 2 times.
cache is just share + replay so they should function the same.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.