1

I have a master template with a component like this:

   <h2>My Heroes</h2>
<ul class="heroes">
  <li *ngFor="let hero of heroes"
    [class.selected]="hero === selectedHero"
    (click)="onSelect(hero)">
    <span class="badge">{{hero.id}}</span> {{hero.name}}
  </li>
</ul>

<app-hero-detail [hero]="selectedHero"></app-hero-detail>]

The Master component is like this:

import { Component, OnInit } from '@angular/core';

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

@Component({
  selector: 'app-heroes',
  templateUrl: './heroes.component.html',
  styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {

  public selectedHero: Hero;

  heroes: Hero[];

  constructor(private heroService: HeroService) { }

  ngOnInit() {
    this.getHeroes();
  }

  onSelect(hero: Hero): void {

    this.selectedHero = hero;
  }

  getHeroes(): void {
    this.heroService.getHeroes()
        .subscribe(heroes => this.heroes = heroes);
  }
}

The Master template is getting data from a service.

On clicking the master's element in list the Child details are displayed.

Using this in master:

 <li *ngFor="let hero of heroes"
[class.selected]="hero === selectedHero"
(click)="onSelect(hero)">

and binding in to

<app-hero-detail [hero]="selectedHero"></app-hero-detail>]

But I am getting this error in the console.

ERROR TypeError: Cannot read property 'name' of undefined at HeroDetailComponent.push../src/app/hero-detail/hero-detail.component.ts.HeroDetailComponent.ngOnInit (hero-detail.component.ts:19) at checkAndUpdateDirectiveInline (core.js:22099) at checkAndUpdateNodeInline (core.js:23363) at checkAndUpdateNode (core.js:23325) at debugCheckAndUpdateNode (core.js:23959) at debugCheckDirectivesFn (core.js:23919) at Object.eval [as updateDirectives] (HeroesComponent.html:10) at Object.debugUpdateDirectives [as updateDirectives] (core.js:23911) at checkAndUpdateView (core.js:23307) at callViewAction (core.js:23548)

My child component is like this:

import { Component, OnInit, Input } from '@angular/core';
import { Hero } from '../hero';
import { HeroService } from '../hero.service';

@Component({
  selector: 'app-hero-detail',
  templateUrl: './hero-detail.component.html',
  styleUrls: ['./hero-detail.component.css']
})
export class HeroDetailComponent implements OnInit {

  @Input() hero: Hero;

  heroes: Hero[];

  constructor(private heroService: HeroService) {  }
  i: string;
  ngOnInit() {
    this.i = this.hero.name

    this.getHeroes();

  }
  getHeroes(): void {

    this.heroService.getHeroes(this.i)
      .subscribe(heroes => this.heroes = heroes);
  }

}

Please Note: I am using the following to bind:

@Input() hero: Hero; // in child component to parent template 

2 Answers 2

3

use the ngOnChanges to check whether the input value is set

  ngOnChanges() {
    if(!this.hero) return null;
    this.i = this.hero.name

    this.getHeroes();

  }
Sign up to request clarification or add additional context in comments.

1 Comment

There are many similar questions to this OP. But this actually solves how we can get the data from API passed from the parent to the @input child property. If you want to console.log the data - it will be undefined on ngOnInit. This is the method (life cycle) where we need to do this - thanks! Perfect answer.
0

onInit, the hero may not be defined, its getting populated after the component has been initialized. You can try using

@Input() set hero (value) {
   if(value) {
      this.i = this.hero.name;
   }
}

Comments

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.