Home > Enterprise >  How to trigger a new api request when using httpClient & shareReplay
How to trigger a new api request when using httpClient & shareReplay

Time:04-19

I am trying to sharereplay() of my httpClient request between multiple components by using the following configuration:

apicaller.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
// import rxjs map
import { map, shareReplay } from 'rxjs/operators';

@Injectable({
  providedIn: 'root',
})
export class ApicallerService {
  peopleindex: number = 1;
  constructor(private _http: HttpClient) {}

  private readonly request = this._http
    .get('https://swapi.dev/api/people/'   this.peopleindex)
    .pipe(shareReplay());

  getData(peopleindex: number = 1) {
    this.peopleindex = peopleindex;
    return this.request;
  }
}

Component1

Should request api to get the details for the id 2

import { Component, OnInit } from '@angular/core';
import { ApicallerService } from '../apicaller.service';

@Component({
  selector: 'app-component1',
  templateUrl: './component1.component.html',
  styleUrls: ['./component1.component.css'],
})
export class Component1Component implements OnInit {
  apiresponse: any;
  editRes: any;
  constructor(private _apicaller: ApicallerService) {}

  ngOnInit(): void {
    this._apicaller.getData(2).subscribe((data: any[]) => { // <-- Notice 2 in the argument
      console.log(data);
      this.apiresponse = data;
    });
  }
}

Component2

Requests for the default id

import { Component, OnInit } from '@angular/core';
import { ApicallerService } from '../apicaller.service';

@Component({
  selector: 'app-component2',
  templateUrl: './component2.component.html',
  styleUrls: ['./component2.component.css']
})
export class Component2Component implements OnInit {

  apiresponse: any = {};
  constructor(
    private _apicaller: ApicallerService
  ) { }

  ngOnInit(): void {
    // get data from api using service
    this._apicaller.getData().subscribe(
      (data) => {
        this.apiresponse = data;
      }
    );
  }

}

However, a new request with the peopleindex = 2 is not being made by component1

To reproduce, you can use my stackblitz setup: https://stackblitz.com/edit/angular-ivy-gdxyy6?file=src/app/component1/component1.component.ts

CodePudding user response:

I would suggest to create API store for such case.

  • for first time it will store API with specific id to store and return initial call.

  • for second time it will take stored API

export class ApicallerService {
  apiStore = new Map();
  constructor(private _http: HttpClient) {}

  private getApiRequest(id) {
    return this._http.get('https://swapi.dev/api/people/'   id).pipe(shareReplay());
  }

  getData(peopleindex: number = 1) {
    if (!this.apiStore.has(peopleindex)) {
      this.apiStore.set(peopleindex, this.getApiRequest(peopleindex));
    }
    return this.apiStore.get(peopleindex);
  }
}

CodePudding user response:

ShareReplay will be beneficial, if you have call for some metadata(masterdata), that will not change across the components(cached/sharing the same data).

To execute the expression with the new values you will need to add getter for request insteed of field.

private get request() { 
    return this._http.get('https://swapi.dev/api/people/'   this.peopleindex);
}

The pattern most of the people uses for calling httpServices is like this.

Create a separate service that calls rest endpoints(wrapper around httpClient).

@Injectable({
  providedIn: 'root',
})
export class ApiService {
  constructor(private _http: HttpClient) {}

  get(url: string) {
    return this._http
    .get(url);
  }

  post(url: string, data) {
    return this._http
    .post(url, data);
  }

}

Then add your feature service that will depend on apiService.

@Injectable({
  providedIn: 'root',
})
export class PeopleService {
  constructor(private _api: ApiService) {}

  getData(peopleindex: number = 1) {
    console.log(peopleindex);
    return this._api
    .get('https://swapi.dev/api/people/'   peopleindex);
  }
}

Call these feature services from your feature components.

export class Component1Component implements OnInit {
  apiresponse: any;
  editRes: any;

  constructor(private _peopleService: PeopleService) {}

  ngOnInit(): void {
    this._peopleService.getData(2).subscribe((data: any[]) => {
      this.apiresponse = data;
    });
  }
}

export class Component2Component implements OnInit {
      apiresponse: any = {};
      constructor(
        private _peopleService: PeopleService
      ) { }

      ngOnInit(): void {
        // get data from api using service
        this._peopleService.getData().subscribe(
          (data) => {
            console.log(data);
            this.apiresponse = data;
          }
        );        
      }
    }

Here is stackblitz link for same.

  • Related