1

In my Angular 4 project I am passing a value form parent component which is coming by a service call. The child component is receiving that value and also available in my HTML. But when I am consoling that passed value in my child component typescript file it is showing undefined.

Here are my code snippets step by step:-

restaurantlayout.component.ts (Parent Component ts file):

import { Component, OnInit, Input } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RestaurantService } from '../../services/restaurant.service';
import { Response } from '@angular/http';

@Component({
  selector: 'app-restaurantlayout',
  templateUrl: './restaurantlayout.component.html',
  styleUrls: ['./restaurantlayout.component.css'],
  providers: [RestaurantService]
})

export class RestaurantlayoutComponent implements OnInit {

    public menuarray;
    public bannerarray;
    public popularArray; //passing data
    constructor(private restaurantservice:RestaurantService) { }

    ngOnInit() {
        this.restaurantservice.getPartcularRestaurantDetailsByidOrSlug()
            .subscribe((data:Response)=>{
                this.menuarray = data.json().menu['menu'] ;
                this.bannerarray = data.json().basicDetails['basicDetails'];
                this.popularArray = data.json().popular['popular'];
            }
        );
    }

}

restaurantlayout.component.html (Parent Alyout Html file)

    <section class="restaurant-details-main">
    <app-restaurantbanner [bannerSection]="bannerarray"></app-restaurantbanner>

</section>
<section class="restaurant-mid-body">
    <div class="wraper">
        <div class="row">
            <app-restaurantmenu [menuSection]="menuarray"></app-restaurantmenu>
            <app-restaurantrecomend [popularSection]="popularArray">

            </app-restaurantrecomend> <!-- passed here  -->
            <app-restaurantbasket>

            </app-restaurantbasket>
        </div>
    </div>
</section>

The child component typescript file code:-

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

import { NgModule } from '@angular/core';

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

    @Input() popularSection:string[];

    public decrementDisabled = true;

  constructor() { }

  ngOnInit() {
    console.log(this.popularSection); //giving undefined but available 
                                      //in HTML file      

}

  increment(popular){
    this.decrementDisabled = false;
    popular.count++;
  }

  decrement(popular){
    popular.count--;
  }

  addTobasket(popularitem){
    popularitem.cost = (popularitem.count*popularitem.item_price);
    this.data.changeBasketState(popularitem);
  }

}
Sandip Nag
  • 968
  • 2
  • 18
  • 34
  • This may be a duplicate of [this question](https://stackoverflow.com/questions/38020950/angular-in-which-lifecycle-hook-is-input-data-available-to-the-component). It looks like the asynchronous service that is populating the `@Input` field is causing this. – Wrokar May 04 '18 at 14:34
  • Value for the input property is set from the parent in an asynchronous operation... – Kyle Krzeski May 04 '18 at 14:42

2 Answers2

4

Your parent component retrieves popularArray with an asynchronous operation, which is then passed to the child as popularSection. This means that when the child component runs its ngOnInit method, the service call hasn't finished yet, and popularSection is still undefined.

Change your ngOnInit to ngOnChanges and you'll see that the variable is first undefined, and as soon as the service returns it, the child will log the correct value.

bugs
  • 14,631
  • 5
  • 48
  • 52
0

Value for the input property is set from the parent in an asynchronous operation.

You could use a setter in the child component to get the value in ts file. Setter for input gets executed whenever change is detected in the input property.

Franklin Pious
  • 3,670
  • 3
  • 26
  • 30