0

I want a service that would return the observable and set a value to field in the same method.

Now my userService.getUserDetails() method looks like this:

private requestUrl: string;
private bic: string;
private id: string;
private name: string;

getUserDetails(): Observable<User> {
this.bic = 'aaa';
this.id= '123';

this.requestUrl = `${configs.api}v1/bics/` + encodeURIComponent(this.bic) + `/ids/` + encodeURIComponent(this.id) + `/users`;

const userObservable = this.http.get<User>(this.requestUrl).pipe(catchError(this.handleError));

userObservable.subscribe(data => this.name = data.name);

return userObservable;
}

I want to do two things when getUserDetails is called: 1) return Observable<User> 2) set the name value so I could access it later in other classes by injecting this service in constructors, without calling the http request again. I think I want to have something like this:

  getName() {
return this.name;
 }

So I'm not sure about the subscribe, because I'm getting undefined after try to use the value. What is the best approach here?

3
  • 1
    You shouldnt return the observable if you subscribe to it, since its a subscription now. What do you get in your logs if you do userObservable.subscribe(data => console.log(data));? Observables are asynchronous, which means you should only work with the variable once the observable returned a value. Commented Apr 17, 2020 at 8:24
  • So what do you suggest? Commented Apr 17, 2020 at 8:25
  • 1
    I wrote it up for you in an answer, feel free to ask any questions if you're unsure Commented Apr 17, 2020 at 8:34

2 Answers 2

1

Try to use the observable like this:

   public name: string;
   public bic: string;
   public id: string;
   public getUserDetails(): Observable<User> {
        this.bic = '...';
        this.id = '...';
        this.requestUrl = `${configs.api}v1/bics/` + encodeURIComponent(this.bic) + `/ids/` + encodeURIComponent(this.id) + `/users`;

        return this.http.get<User>(this.requestUrl).pipe(catchError(this.handleError));
    }

Ideally, this method is in a service and does nothing else but to return the observable and do error-handling if needed.

In your component you could have this:

    constructor(private readonly _yourService: YourService) {}

    public ngOnInit(): void {
    this.getUserDetails();
    console.log(this._yourService.name) // can be undefined, since the observable is asynchronous and probably isnt finished yet
    }

    public getUserDetails(): void{
    this._yourService.getUserDetails().subscribe(
    data => {
    this._yourService.name = data.name;
    // start doing other things, this.name should be defined, if your service returned the data correctly.
    }
    )
    }

Alternatievly, you can also do all of this in your service, it's really your choice of design.

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

7 Comments

You see the problem is that I don't want to call the http request twice. The scenario that I want is: 1) I open the page, it calls getUserDetails, it returns the Observable(I really need the observable) and also sets the name variable. 2) Later I call this service and get the assigned variable not calling the http request for the second time. Is it even possible to do something like this?
You can alternatively store the variable in your service for later use, this calls the http request once and assigns name once its done. If you dont want getUserDetails() to be called again you can also store a bool in your service that serves as a check if the function has already been called and conditionally call the method in ngOnInit()
So yes, the question is how do I store the variable after calling the http request, so I can use it later?
I've updated the answer again, it does now store the fetched name in the service, where you can access it from any component.
Hm, the other service can just access the stored variable in the user service, should be easy as that. Assuming your component has called the getUserDetails() method once.
|
0

use "tap", in your service

name:any;
const userObservable = this.http.get<User>(this.requestUrl).pipe(
tap((res)=>{
    this.name=res;
}),
catchError(this.handleError)
);

Sometimes it's used a kind of "cache"

name:any;
const userObservable = (this.name)?of(name):
  this.http.get<User>(this.requestUrl).pipe(
    tap((res)=>{
      this.name=res;
    }),
      catchError(this.handleError)
    );

So, you always can subscribe to the function, the first time, make the call to http, the second use the value of name -of(name) return an observable

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.