Angular 2 cache observable http result data

Avi picture Avi · Jan 9, 2017 · Viewed 34.6k times · Source

I have a service that fetches data via the HTTP service and returns an observable object.

After the first call I would like to cache the result internally in the service, and once a new component will try to get the data it will take it from the cached result.

Is there a simple solution for this?

Answer

jonrsharpe picture jonrsharpe · Jan 9, 2017

If you lean into observables as a means of sharing data, you can adopt the following approach:

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';

import { Observable, ReplaySubject } from 'rxjs';

@Injectable()
export class CachedService {
 
  private dataSubject = new ReplaySubject<Response>(1);
  
  data$: Observable<Response> = this.dataSubject.asObservable();
  constructor(private http: Http) { }

  fetch() {
    this.http.get(...).subscribe(res => this.dataSubject.next(res));
  }
}

This will make an HTTP call when the fetch method is called, and any subscribers to service.data$ will get the response from the ReplaySubject. As it replays earlier values, any subscribers who join after the HTTP call resolves will still get the previous response.

If you want to trigger an update, you can just call service.fetch() to kick off a new HTTP call and all subscribers will be updated once the new response arrives.

Your components would then look something like:

@Component({ ... })
export class SomeComponent implements OnInit {

  constructor(private service: CachedService) { }

  ngOnInit() {
    this.service.fetch();
    this.service.data$.subscribe(...);
  }
}

I've recently written a blog article on this approach for my colleagues: http://blog.jonrshar.pe/2017/Apr/09/async-angular-data.html