0

I am using angular 2 for my personal project. So here's the simplified scenario with some sudo-code.

app
 |- main.ts            /* bootstrap the app */
 |- app.component.ts   /* basically with a template: `<nav></nav>
 |                                                    <router-outlet></router-outlet>`.
 |                        And also have providers: [CatService] */
 |- nav.component.ts   /* a navigation bar where each cat's name is an option. 
 |                        ngOnInit(){ this._catService.getCats().then(assignCats) } */
 |
 |- cat.components.ts  /* show the cat's detail selected from the nav component 
                          ngOnInit(){ this._catService.getCat().then(assignCat); } */
 |
 |- cat.service.ts     /* getCats() method to send query to a database for all the cats */

Ok. I hope this doesn't look too complicated.

The only problem is, I am calling the this._catService.getCats() which sends query to the database in both nav.component and cat.component. But there actually has no point sending the query twice as I already know the data is not going to change often. I can only thought of two ways of handling this now:

  1. Cache the result of the database call in this._catService.getCats() so that in the second call, it can return the cached value instead of sending a second query.

  2. Do the query at app.component then pass the result to nav and cat as @input. But then this means later if I have a new component I have to pass the result to it too? then end up the template of app.component might become something like:<nav [cats]="queriedCats"></nav>, <cat [cats]="queriedCats"></cat>, <somecomponent [cats]="queriedCats"></somecomponent>... which looks really bad to me.

What do you think? Which way is the prefered way to do it?

Jason Yu
  • 311
  • 2
  • 12

2 Answers2

1

Which way is the prefered way to do it?

The first way is a better fit and leverages better the dependency injection mechanism of Angular.

I am calling the this._catService.getCats() which sends query to the database in both nav.component and cat.component. But there actually has no point sending the query twice as I already know the data is not going to change often.

The fact that the query result does not change much is actually and implementation detail of you _catService: there's no need to let other components know about it, encapsulate that detail in it.

And, you said it yourself, the query result is almost constant, but still changes (or may begin to change more frequently). Let the service deal with that and free the rest of the system from the burden.

Should I still return a promise from getCats()?

Yes, you could return Promises. A good example of that can be found in the demo plunker (check the app/hero.service.ts file, method getHeroes()) of the Services tutorial page of angular docs.

You could also return an Observable: that is somewhat more common in Angular2, and Observable is, in fact, the kind of object returned by Htto#get(). Angular docs also explains it well here: RxJS Observable of HTTP Responses.
They too have a demo plunker (again, check the app/hero.service.ts file, method getHeroes()) showing how to return Observables. Open the two demos and compare, I think it would be very useful to you.

acdcjunior
  • 132,397
  • 37
  • 331
  • 304
0

I will leverage the do operator of observables for this. Here is a sample:

export class CatsService {
  getCats() {
    if (this.cachedCats) {
      return Observable.of(this.cachedCats);
    } else {
      return this.http.get(...)
         .map(res => res.json())
         .do(data => {
           this.cachedCats = data;
         })
    }
}
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360