Azim Saiyed
Azim Saiyed

Reputation: 582

Reuse the object returned from HTTP response without making another API call in Angular 4

I am using promise to retrieve a User-Details object in a Angular 4 app using Typescript.

Now, I am using part of that object at two different places in my application using simple get request. Something like this :

private _firstName: String;
private _email: String;

  get userDetail(): Promise<any> {
  return this.http
  .get(this._userDetailsURL)
  .toPromise()
  .then((response) => {
    this._firstName = response.json().firstName;
    this._email = response.json().email;
  })
  .catch((err) => err);
  }

  get firstName(): String {
    return _firstName;
  }

  get email(): String {
    return _email;
  }

So, how do retrieve firstName and email using their getter functions after the promise is resolved ?

I understand that I can reuse the same get() request twice but I don't want to make an unnecessary api call. I want to retrieve these values multiple times and make a single API call.

Thanks

Upvotes: -1

Views: 3120

Answers (2)

LLai
LLai

Reputation: 13416

As of rxjs 5.4.0 you can use shareReplay (https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/sharereplay.md)

You basically store the observable sequence and return it when components subscribe to it.

// service.ts
observable$ = this.http
    .get(this._userDetailsURL)
    .map(res => res.json())
    .shareReplay();

getUserDetail(){
    return this.observable$
        .toPromise();
}

now when a component subscribes to this, it will share the same api request (regardless if calls happen simultaneously or happen later). Here is a working plnkr (https://plnkr.co/edit/drngeofZsXuG9LfJkFob?p=preview) look at the console logs to see shareReplay work.


Taking this a step further, you can implement a way to clear the shareReplay. For example if a user logs out, you would want to clear the user data.

// service.ts
$observable;

getUserDetail(){
    // if no observable sequence found, create sequence
    if(!this.observable$){
        this.observable$ = this.http
            .get(this._userDetailsURL)
            .map(res => res.json())
            .shareReplay();
    }

    return this.observable$
        .toPromise();
}

clearUserCache(){
    this.observable$ = null;
}

Now when a user logs out, you can call clearUserCache() and when something subscribes to getUserDetail(), another http request will be initiated.

Upvotes: 1

Gosha_Fighten
Gosha_Fighten

Reputation: 3868

You can check if _firstName and _email already exist. If so, just return them and don't call your server. In this way, you can always use the userDetail method to get your data.

private _firstName: String;
private _email: String;

  get userDetail(): Promise<any> {
  if (this._firstName && this._email) {
    return new Promise((resolve, reject) => {
       resolve({firstName: this._firstName, email: this._email})
    })
  }
  return this.http
  .get(this._userDetailsURL)
  .toPromise()
  .then((response) => {
    this._firstName = response.json().firstName;
    this._email = response.json().email;
    return {firstName: this._firstName, email: this._email}
  })
  .catch((err) => err);
  }

Upvotes: 0

Related Questions