6

I am using angular (v6) service to fetch data from backend and store in a variable. I want to call the api only once and serve the data whenever required to different components.

The problem is that I am calling getPlans() function in the service from different components to get data and for each call, I am seeing a api call in the network tab of the browser.

How to avoid calling each time I call getPlans() function and serve the data calling the api once and storing it to a variable?

export class PlansService {
  private plansData:any = {};

  constructor(private httpCallService: HttpCallService, private http: HttpClient) { 

    this.plansData = this.httpCallService.getHttpResponse("GET_PLANS");

  }
  getPlans(): Observable<any>{
    return this.plansData;
   }

}
1
  • I would recommend you to use behaviour subject for keeping data and subscribing to it, so you get changes. Also get and refresh methods for getting data or just refresh store (with behavior subject you will get changes). Commented May 9, 2019 at 23:03

2 Answers 2

5

This can be done with RxJs's shareReplay(). According to the Changelog,

shareReplay returns an observable that is the source multicasted over a ReplaySubject. That replay subject is recycled on error from the source, but not on completion of the source. This makes shareReplay ideal for handling things like caching AJAX results, as it's retryable. It's repeat behavior, however, differs from share in that it will not repeat the source observable, rather it will repeat the source observable's values.

Which makes the user of shareReplay() perfect for your use case.

Remember to import shareReplay() on your service too.

import { shareReplay } from 'rxjs/operators';
.
.

export class PlansService {
  private plansData: Observable<any>;

  constructor(private httpCallService: HttpCallService, private http: HttpClient) { 

    this.plansData = this.httpCallService.getHttpResponse("GET_PLANS")
      .pipe(
        shareReplay()
      );

  }

  getPlans(): Observable<any>{
    return this.plansData;
   }

}

Then, you can return the observable on the componenet that requires it, and if you look at the network request tab on your Inspect Element tool, no additional HTTP requests are fired since the observable with the cached values are returned everytime getPlans() is called.

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

Comments

4

You can use ReplaySubject or BehaviorSubject to get that working, if you use ReplaySubject you have to specify how many old values you want to store so subscribers can access later, BehaviorSubject can keep only the last value

 import { ReplaySubject } from 'rxjs';

 ....
 @Injectable()
 export class SharedService {
 plans$: Observable<Plan[]> = this.plansSubject.asObservable(); 
 private plansSubject = new ReplaySubject<Plan[]>(1);

 constructor(private http: HttpClient) { }
 getPlans(){
   this.http.get().subscribe(res => this.plansSubject.next(res.plans)); // get array of plans
 }
}

and you can get your data in your components like this:

constructor(private sharedService: SharedService) { }

ngOnInit() {
 this.sharedService.getPlans(); // to get called only the first time to get data
 this.service.plans$.subscribe(...); // you have your data here without anu additional http call 
}

and in case you want to refresh the data, you can call the method

this.sharedService.getPlans();

for BehaviorSubject it's exactly the same thing, here what will change

plans$: Observable<Plan[]> = this.plansSubject.asObservable(); 
private plansSubject = new BehaviorSubject<Plan[]>;

you can subscribe inside your component to get the data or you can access it using BehaviorSubject.value

constructor(private sharedService: SharedService) { }

ngOnInit() {
 this.service.plans$.subscribe((plans) => console.log(plans));
 // or access the value directly
 console.log(this.service.plans$.value)    
}

Comments

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.