Nitin Tayal
Nitin Tayal

Reputation: 59

Angular observable subscribe showing undefined

I have written down a component and a service to show the detail of some object, however when subscribing and seeing in console it shows undefined. I have tried it a lot, any help would be appreciated.

I have shown all both component and service below to see if i am making any mistake here.

My component is below:-

import { Component, Input } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Location } from '@angular/common';
import { filter, map } from 'rxjs/operators';

import { HeroService }  from '../heroes/hero.service';
import { Hero } from '../hero';

@Component ({
selector : 'app-hero-detail',
templateUrl : './hero-detail.component.html'
})

export class HeroDetailComponent {
//@Input() hero : Hero; 
hero : Hero; 
constructor(
    private route: ActivatedRoute,
    private heroService: HeroService,
    private location: Location
  ) {}

  ngOnInit(): void {

    this.getHero();
  }

  getHero(): void {
    const id = +this.route.snapshot.paramMap.get('id');

    this.heroService.getHero(id).map(hero => {this.hero = hero;console.log(hero);}).subscribe();
  }

  goBack(): void {
    this.location.back();
  }
}

My service is as below:-

import { HttpClient } from "@angular/common/http";
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/observable';
import { of } from 'rxjs/observable/of';
import 'rxjs/add/operator/find';
import 'rxjs/add/operator/map';

import { Hero } from '../hero';


import { MessageService } from './message.service';

@Injectable()

export class HeroService  {
hero : Hero;
private heroesUrl = 'assets/api/mock-heroes.json';
constructor(private _http: HttpClient, public messageService : MessageService) { }

getHeroes(): Observable <Hero[]> {
this.messageService.add('HeroService: fetched heroes');
return this._http.get<Hero[]>(this.heroesUrl);
//return of(HEROES);
}

getHero(id: number): Observable<Hero> {
// Todo: send the message _after_ fetching the hero
this.messageService.add(`HeroService: fetch hero id=${id}`);
return this._http.get<Hero>(this.heroesUrl).find(hero => hero.id === id);
}

}

Here is my data set:-

[
 { "id": "11", "name": "Mr. Nice" },
 { "id": "12", "name": "Narco" },
 { "id": "13", "name": "Bombasto" },
 { "id": "14", "name": "Celeritas" },
 { "id": "15", "name": "Magneta" },
 { "id": "16", "name": "RubberMan" },
 { "id": "17", "name": "Dynama" },
 { "id": "18", "name": "Dr IQ" },
 { "id": "19", "name": "Magma" },
 { "id": "20", "name": "Tornado" }
]

Below is my template:-

<div *ngIf="hero">

<h2>{{ hero.name | uppercase }} Details</h2>
<div><span>id: </span>{{hero.id}}</div>
<div>

<label>name:
<input [(ngModel)]="hero.name" placeholder="name">
</label>

<button (click)="goBack()">go back</button>

</div>

Upvotes: 0

Views: 635

Answers (1)

JB Nizet
JB Nizet

Reputation: 692151

Your JSON contains an array of Heroes. So

return this._http.get<Hero>(this.heroesUrl).find(hero => hero.id === id)

can't possibly be correct: the HTTP observable emits a single event, which is an array of heroes. It does not, as your code expects, emit multiple events which are each one Hero.

What is should be is

return this._http.get<Array<Hero>>(this.heroesUrl)
  .map(heroes => heroes.find(hero => hero.id === id));

Also, the line

this.heroService.getHero(id).map(hero => {this.hero = hero;console.log(hero);}).subscribe();

should really be

this.heroService.getHero(id).subscribe(hero => this.hero = hero);

You're abusing map(), which should be used to transform an event into something else, and not to produce side-effects.

Upvotes: 1

Related Questions