1
votes

I am trying to reuse cached data. If there is no cached data then use http to get data. If there is cached data then use the cached data in observable.

here is the data service.ts

import {Injectable} from 'angular2/core';
import {Http, Response, Headers, RequestOptions} from 'angular2/http';
import {Observable} from 'rxjs/Observable';
import {Observer} from 'rxjs/Observer';
import 'rxjs/add/operator/share';

import {Hero} from './hero';
//import {HEROES} from './mock-heroes';


@Injectable()
export class HeroService {
  private _baseUrl: string;
  private _cachedHeroes; 

  private _heroesObserver: Observer<Hero[]>;
  private _heroObserver: Observer<Hero>;
  heroes$: Observable<Hero[]>; 
  hero$:   Observable<Hero>; 
  public _dataStore: { heroes: Hero[], hero: Hero };

  constructor (private http: Http) {
        this._dataStore = { heroes: [], hero: {_id: null, name: null} };
        this.heroes$ = new Observable(observer =>  this._heroesObserver = observer).share();
        this.hero$   = new Observable(observer =>  this._heroObserver = observer).share();
        this._baseUrl = 'http://localhost:8081/api/hero/';  // URL to web api
  }

  loadHeroes() {
      if (this._dataStore.heroes.length === 0) {
        this.http.get(`${this._baseUrl}readAll`)
                 .map(response => response.json()).publishReplay(null,1).refCount()
                 .subscribe(data => {
                                     this._dataStore.heroes = data;
                                     this._heroesObserver.next(this._dataStore.heroes);
                                    }, 
                             error => console.log('Could not load heroes.')
                            );
      }
      else {
       //   Observable.of(this._dataStore.heroes)
       this.heroes$.map(data =>this._dataStore.heroes)
       .publishReplay(null,1).refCount()   
       .subscribe(data => {
                                     this._dataStore.heroes = data;
                                     this._heroesObserver.next(this._dataStore.heroes);
                                     console.log(this.heroes$);
                                    }, 
                             error => console.log('Could not load heroes.')
                            );
      //console.log(this._heroesObserver);          
      }
  }
}

The http.get().map().subscribe() is always working. this._heroesObserver.isUnsubscribed always shows false.

But when there is cached data this._heroesObserver.isUnsubscribed always shows true.

The component calls to this function from within ngOnInit()

  ngOnInit() {
    this._heroService.loadHeroes();       
    this.heroes = this._heroService.heroes$;
    this.heroes.subscribe(data => {
                                    data.forEach((h, i) => {
                                        console.log(h); 
                                    });
                                  }, 
                          error => console.log('Could not get hero.')
                         );
  }

Does that matter? I think not. What can I do to make it work?

Updated the code to add .publishReplay(null,1).refCount().

Now the refCount increments and the isUnsubscribed always shows false. However, the component still cannot get data. The first time when there is no cached data console.log in the component prints all data correctly. But when there is cached data, the console.log prints nothing.

1

1 Answers

1
votes

Use publishReplay(1) to change your observable into a hot observable that will remember and replay the last value and supply it to late subscribers:

import * as Rx from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/publishReplay';

this.heroes$ = http.get(...).map(...).publishReplay(1).refCount();

this.heroes$.subscribe(...);

The last replayed value is essentially the cached value, which gets replaced when a new http request is made