0

I am currently stuck with a simple problem. I have a service called UserService that aims to be an API layer. I would like to call its method getProfile() in this way:

  • If it is the first time that method is called, it will make a request to my API to retrieve the profile, it will be saved to a variable, and then return it in the form of Observable to the component that called it.
  • If that variable has the profile in it already, just return that, in order to avoid unnecessary network overhead.

I have tried different approaches for this but can't get it completely working (I am a newbie on Angular and rxjs).

This is what I have so far.

getProfile() method from the UserService:

public getProfile(): Observable<any> {
if (this.profile) {
  return Observable.of(this.profile);
} else {
  this.http.get(URLS.URL_GET_PROFILE,
    { headers: this.authZeroService.getAuthorizationHeaders() })
    .subscribe(res => {
      this.profile = res.json().user.profile;
      return Observable.of(this.profile);
    });
  }
}

Then calling it from the profile component:

userService.getProfile().subscribe(profile => {
  console.log(profile);
});
Robin Dijkhof
  • 18,665
  • 11
  • 65
  • 116
Cristian
  • 370
  • 3
  • 8
  • Your `http.get` branch doesn't match the method's interface; returning in the `subscribe` callback doesn't do anything. Read the RxJS docs; you probably want to `.map`. – jonrsharpe Mar 10 '18 at 23:09

2 Answers2

0

Save the profile in a subject in a service:

export class ProfileService{

    private $profile: Subject<Profile> = new Subject();

    //fetch it the first time.
    contructor(http: HttpClient){
        this.http.get<Profile>('some_url).subscribe(res => {
            this.$provile.next(res);
        });
    }

    //The get the profile for you app:
    public getProfile(): Observable<Profile> {
        return this.$profile.asObservable();
    }

}
Robin Dijkhof
  • 18,665
  • 11
  • 65
  • 116
  • 2
    This loads the profile as soon as the service is created, not on the first call to it as requested in hue question. – Ingo Bürk Mar 10 '18 at 23:32
  • As @IngoBürk stated this doesn't fully comply what I needed, but I thank you for the snippet. Anyway I have tried your solution and it just returns null – Cristian Mar 11 '18 at 15:08
  • @Cristian BTW, I think you just want to use `shareReplay(1)` which will cache the result itself and have reasonable error behavior. No need for a variable. – Ingo Bürk Mar 11 '18 at 15:13
  • [See my answer here](https://stackoverflow.com/questions/48568104/initialize-cache-when-it-is-used/48570435#48570435). – Ingo Bürk Mar 11 '18 at 15:14
0

I finally got it working in a very similar way that I thought it could be done. I know there are better and simpler ways of doing the same.

Class variables from UserService:

private profile: any;
private profile$: Observable<any>;

getProfile() method:

public getProfile(): Observable<any> {
if (this.profile) {
  return Observable.of(this.profile);
} else if (this.profile$) {
  return this.profile$
} else {
  this.profile$ = this.http.get(URLS.URL_GET_PROFILE,
    { headers: this.authZeroService.getAuthorizationHeaders() })
    .map(res => {
      this.profile$ = null;
      this.profile = res.json().user.profile;
      return this.profile;
    })
    .share();
  return this.profile$;
  }
}

Then just subscribe from any component. This solution is based on this one https://stackoverflow.com/a/36291681/7048554

Cristian
  • 370
  • 3
  • 8