Lev
Lev

Reputation: 15734

Observable returned by service won't complete

I have a service that uses angular's http service

@Injectable()
export class MyService {

  constructor(private http: Http) { }

  getThings() {
    return this.http.get('url').map((res) => {
      // massage data here and return massaged data
    });
  }
}

I use the service like this

this.myService.getThings.subscribe(
  things => {},
  err => {},
  () => {
    // never completes...
  });

How come myService.getThings() never completes although http.get('url') completes ?

How can I make myService.getThings() complete ?

Upvotes: 0

Views: 3480

Answers (4)

yoonjesung
yoonjesung

Reputation: 1208

The http.get('url') does not "complete" because all that does is map the response sent from your server.

One thing to note here about Observables: They do not actually do anything until they are subscribed to. Secondly, the following code:

return this.http.get('url').map((res) => {
  // massage data here and return massaged data
});

returns an Observable, which is just a function that returns a stream of data.

Another thing to note about Observables is that not all Observables will complete inherently. Observables only complete if their source completes. In this case, the http.get() function does complete, so that is not a concern for you.

Lastly, Observables will not complete if they trigger an error. In the case of the http.get() function, an error is triggered if the server produces any response that is not a 200 level response.

I suggest that you change your getThings function to include the catch operator:

import {Http, Response} from '@angular/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';

return this.http.get('url')
   .map((res) => {
      // massage data here and return massaged data
   })
   .catch((error: Response) => {
      return Observable.throw(error.status);
   });

If an error occurs from the get() request, it will return an Observable containing the status from the server. Then you can take a look at the status and see what the issue is.

Upvotes: 0

Alex Beugnet
Alex Beugnet

Reputation: 4071

This is possible that it does not complete because of websockets or other mecanisms as stated in the github issue : https://github.com/angular/angular/issues/7865 ; but here are two plunkr with Angular2 and Angular4, both using a mock json file through HTTP, and in both cases the observable completes correctly.

In both cases I've setup a similar case to yours :

this.toto().subscribe(
      (result) => {
        console.log('result => ', result);
      },
      (error) => {
        console.log('error => ', error);
      },
      () => {
        console.log('comlete');
      }
    });

  toto() {
    return this.http
    .get('test.json')
    .map((res) => res.json());
  }

Plunkr1 : http://plnkr.co/edit/hoIyMHl8abhaG7BYVyns?p=preview

Plunkr2 : http://plnkr.co/edit/siVrOIIvT1uWP36LkiOZ?p=preview

Upvotes: 0

Henrique Souza
Henrique Souza

Reputation: 49

The "complete" block won't be executed if some error occurred in the process. (Does not work as a Finally).

Put some log in all steps to find if occurred some error.

Upvotes: -1

Jota.Toledo
Jota.Toledo

Reputation: 28454

I would suggest that you use the finally operator in case that you want to execute code when the stream emits its last value (completes).

For example:

//Inside of a component
this.fooService.getFoos().
finally(()=>console.log("Completed"))
.subscribe(foos => this.foos = foos);

Upvotes: 0

Related Questions