34

I've been banging my head against this one trying to figure it out, and no amount of documentation I've been able to read has given me an answer to my question.

I have a service which is speaking directly to an API and returning an observable event which under normal circumstances I would subscribe to and do what I want with the data, however in a secondary service which utilizes the requests from the restful service, I need to be able to return values from the request.

getSomething() {
    return this._restService.addRequest('object', 'method').run()
        .subscribe(
            res => {
                res;
            },
            err => {
                console.error(err);
            }
        );
}

returnSomething() {
    return this.getSomething();
}

In the quick example above, I want to know if there is any way I can return res from getSomething() within returnSomething(). If it's not achievable in this way, what is the alternative? I will add that the _restService is pretty heavily relied upon and I don't really want to start messing with that.

2
  • Where are you using returnSomething()? You know this is an asynchronous operation so you can't "get" the result immediately. You can maybe return the (res) inside subscribe in returnSomething() but i don't know if it'd be practical. Commented Jun 16, 2016 at 18:55
  • The example above would be contained within a service, and the call to the method would be in multiple components, which is why I would like to just return the res value, as it would save quite a bit of code. I'd also need to be able to compare the results of two or more similar methods. Commented Jun 16, 2016 at 18:57

3 Answers 3

49

Since http calls and the like are async, you get an Observable instead of a synchronous value returned. You have to subscribe to it, and in the callback in there you get the data. There is no way around that.

One option would be to place your logic in the subscribe call

getSomething() {
    return this._restService.addRequest('object', 'method').run()
        .subscribe(
            res => {
                // do something here
                res;
            },
            err => {
                console.error(err);
            }
        );
}

But the way I like doing it is to add a callback, to inject the logic from outside (maybe a component, maybe another service):

getSomething(callback: (data) => void) {
    return this._restService.addRequest('object', 'method').run()
        .subscribe(
            res => {
                callback(res);
            },
            err => {
                console.error(err);
            }
        );
}

And in your component or wherever:

this._yourService.getSomething((data) => {
    // do something here
    console.log(data);
});
Sign up to request clarification or add additional context in comments.

4 Comments

Definitely a new way to think about using services, this turned out to be exactly what was needed!
I landed here presumably because of the Observable keyword. I need to do something similar to this. What type of service has a method .run()? I cannot use this on a regular Angular 2 http service. thx
got around hours to figure out the error. Thank you for this answer.
what about Subject Behavior
4

I had a similar issue. My solution was to convert the observable into a promise with .toPromise() (and use async - await to return it and catch errors). You can convert your code into something like:

 async getSomething() {
     try{
         return await this._restService.addRequest('object', 'method').run().toPromise()
      } catch (err){
       console.error(err);
	  }
  }

1 Comment

This is not a solution for the initial question. You do not return the data that way, but a Promise and you would still have to "subscribe" to it (with then) to get the final data.
0

I didn't use this myself, but I believe it should work in theory (:

// service.ts
getSomething() {
  let subject: Subject = new Subject();
  this._restService.addRequest('object', 'method').run()
    .subscribe(subject);
  return subject;
}

// this can be removed (;
returnSomething() {
  return this.getSomething();
}

// component.ts
ngOnInit() {
  this.service.returnSomething()
    .subscribe(res => console.log(res), err => console.log(err));
}

Check subject docs for more info. You can use different types of subject, for example BehaviorSubject has value property you can access...

ngOnInit() {
  // if you use BehaviorSubject
  this.service.returnSomething().value
}

Here's the working plunker...

2 Comments

This won't work, since subject gets returned before you get the data from subscribing to it.
@rinukkusu True, for initial value, should work after.. You can set initial value for BehaviourSubject tho'... Or .filter(Boolean) before subscribing to the observable...

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.