3
votes

My getHero service observable is not getting invoked in NgOnInIt in the HeroDetail Component.

I'm able to use HTTP to get & display the data table & route to a detail page when the row is clicked. Then I'm using the url's "id" parameter to get the id but the same is not working with the getHero function to get the particular row details.

ID is shown in console but hero comes as undefined. I've tried a lot of stuffs but none has worked so far. Any help would be highly appreciated.

Below is my code for reference.

hero.service.ts

import { Injectable }              from '@angular/core';
import { Http, Response }          from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import { Hero } from './hero';

@Injectable()
export class HeroService {
heroes: Hero[];
hero: Hero;

  private heroesUrl = 'SERVICE URL';
  constructor (private http: Http) {}

  getHeroes(): Observable<Hero[]> {
    return this.http.get(this.heroesUrl)
                    .map(this.extractData)
                    .catch(this.handleError);
  }
  private extractData(res: Response) {
    let body = res.json()['data'];
    console.log(body);
    return body || { };
  }
  private handleError (error: Response | any) {
    // In a real world app, you might use a remote logging infrastructure
    let errMsg: string;
    if (error instanceof Response) {
      const body = error.json() || '';
      const err = body.error || JSON.stringify(body);
      errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
    } else {
      errMsg = error.message ? error.message : error.toString();
    }
    console.error(errMsg);
    return Observable.throw(errMsg);
  }

getHero(id: number): Observable<Hero> {
    return this.getHeroes()
      .map(heroes => heroes.find(hero => hero.cc_id == id));
  }
}

hero-detail.component.ts

import { Component } from '@angular/core';
import { Router, ActivatedRoute, Params } from '@angular/router';
import { HeroService } from './hero.service';
import { Hero } from './hero';

@Component({
  template: `
  <h2>INNER PAGE {{ this.id }}</h2>
  `,
  providers: [HeroService]
})

export class HeroDetailComponent {

errorMessage: string;
  hero: Hero;
  heroes: Hero[];
  id: number;
  mode = 'Observable';

  constructor (
  private service: HeroService,
  private route: ActivatedRoute,
  private router: Router
  ) {}


ngOnInit() { this.getHeroes() }

  getHeroes() {
  this.id = this.route.snapshot.params['id'];
  console.log(this.id);

   this.service.getHero(this.id).subscribe(hero => this.hero = hero);
   console.log(this.hero);
  }

}
2

2 Answers

1
votes

You are logging this.hero before call is done. This is because Http calls are done asynchronous.

getHeroes() {
    this.id = this.route.snapshot.params['id'];
    console.log(this.id);

    this.service.getHero(this.id).subscribe(hero => {
         this.hero = hero;
         console.log(this.hero);
    });
}
0
votes

When using Observables, the code outside the Observable is executed before the actual subscribe block executes because Observables are asynchronous. The response from the server comes in the subscription's callback. Try changing the code to following:

this.service.getHero(this.id).subscribe(hero => {
     this.hero = hero;   // assign the class variable values here
     console.log(this.hero); 
  });
}