AVJT82
AVJT82

Reputation: 73357

HTTP: Angular 2+TS How to use Observables in HTTP

I found an example from angular.io. This example is very similar to my app, with same kind of methods. This example is using Promises, but I'm using Observables. If I use this example as a reference, I have every method working in my app, except the getHero method in the service, and the ngOnInit in the HeroDetailComponent. So I'm wondering if someone can help and convert this method to an observable, because I'm having trouble with the syntax. Here is the codes I need converted to Observable and the plunker

//HeroService
  getHero(id: number) { // my id is String
    return this.getHeroes()
               .then(heroes => heroes.filter(hero => hero.id === id)[0]);
  }


//HeroDetailComponent
  ngOnInit() {
    if (this.routeParams.get('id') !== null) {
      let id = +this.routeParams.get('id');
      this.navigated = true;
      this.heroService.getHero(id)
          .then(hero => this.hero = hero);
    } else {
      this.navigated = false;
      this.hero = new Hero();
    }
  }

So I want something like this:

//HeroService
public getHero(id: string) {      
    return this.getHeroes()
    .subscribe(heroes => this.heroes.filter(hero => heroes.id === id)[0]); //BTW, what does this [0] mean??        
}

EDIT: I had to actually retrieve the list directly, it didn't work with return this.heroes as suggested in answers below. Working example:

public getById(id: string) {   
    //return this.getHeroes() <---- didn't work
    return this.http.get('someUrl') // WORKS!
    .map(heroes => this.heroes.filter(hero => hero.id === id)[0]);           
}

Now I'm still having trouble with my ngOnit, and I can't really understand why!

ngOnInit(){
    let id = this._routeParams.get('id');
    this.heroService.getById(id)
    //console.log("retrieved id: ",id ) <----- gives correct id!
    .subscribe(hero => this.hero = hero); 
    //console.log("hero: ", this.hero); <----- gives undefined!
}

EDIT2, still getting undefined when trying to move to the detail page :( I think you had one bracket to much in your answer, tried to look and get the correct places for the brackets?

ngOnInit(){
    let id = this._routeParams.get('id');
    this.heroService.getById(id)
    .subscribe(heroes => {
      // this code is executed when the response from the server arrives
      this.hero = hero 
    });
    // code here is executed before code from the server arrives
    // even though it is written below
}

Upvotes: 2

Views: 543

Answers (2)

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 657308

If you call subscribe() on an Observable a Subscription is returned. You can't call subscribe() on a subscription.

Instead use just an operator (map()) and use subscribe() on the call site:

public getHero(id: string) {      
    return this.getHeroes()
    .map(heroes => this.heroes.filter(hero => heroes.id === id)[0]);
}

ngOnInit(){
    let id = this._routeParams.get('id');
    this.heroService.getHero(id)
    .subscribe(hero => this.hero = hero);
}

In contrary to subscribe(), map() also operates on an Observable but also returns an Observable.

[0] means to just take the first item of the filtered heroes.

update

ngOnInit(){
    let id = this._routeParams.get('id');
    this._searchService.getById(id)
    .subscribe(searchCase => {
      // this code is executed when the response from the server arrives
      this.searchCase = searchCase; 
      console.log("id: ", this.searchCase); 
    });
    // code here is executed before code from the server arrives
    // event though it is written below
}

This code is a function

    searchCase => {
      // this code is executed when the response from the server arrives
      this.searchCase = searchCase); 
      console.log("id: ", this.searchCase); 
    }

that is passed to subscribe() and the Observable calls this function when it has new data for the subscriber. Therefore this code is not executed immediately but only when the observable emits new data.

Code that comes after subscribe() is executed immediately and therefore before above function and therefore this.searchCase does not yet have a value.

Upvotes: 2

Maximilian Riegler
Maximilian Riegler

Reputation: 23506

This is a way you can do it:

//HeroService
public getHero(id: string) {      
    return this.getHeroes()
        .map(heroes => this.heroes.filter(hero => heroes.id === id)[0]);  
}

//HeroDetailComponent
ngOnInit(){
    let id = this._routeParams.get('id');
    this.heroService.getHero(id)
        .subscribe(hero => {
            // your code here
        });
}

The [0] is an array accessor. You're selecting the first element on array index 0 with it. You need this, because Array.filter() returns a new array with the filtered values, but you only want one hero.

Upvotes: 1

Related Questions