7

I am trying to pass data that is dynamic to a child component. But I always get the data as undefined in the child component. Below is what I am doing.

ParentComponent.ts

results: any[];
ngOnInit() {
this.http.get('url').subscribe(data => this.results = data);
}

ParentComponent.html

<app-childComponent [dataNeeded]=results></app-childComponent>

ChildComponent.ts

@Input('dataNeeded') dataNeeded: any[];
ngOnInit() {
 console.log(dataNeeded); //Always undefiend
}

So as expected, it doesn't wait for the asynchronous call and returns me undefined. How do i pass the dynamic data to the component?

Ravi Yadav
  • 637
  • 1
  • 9
  • 21

4 Answers4

5

You might try OnChanges lifecycle hook method.

In your case, you would need to add it to your child component like so:

ngOnChanges(changes) {
  if (changes['dataNeeded'] && this.dataNeeded) {
    console.log(this.dataNeeded);
  }
}

PS Also I just noticed the wrong syntax in your ChildComponent.ts, it is missing this:

ngOnInit() {
 console.log(this.dataNeeded);
}
4

The problem is that the UI thread will render the child component before the subscribe from the observable finished.

you need to do it like this:

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

constructor(private ref: ChangeDetectorRef) {}
ngOnInit() {
   this.http.get('url').subscribe(data => { 
     this.results = data;
     this.ref.markForCheck();
   });
}

and in the HTML you have to test the value first.

<ng-container *ngIf="results != null">
    <app-childComponent [dataNeeded]=results></app-childComponent>
</ng-container>

A little description, the .markForCheck() will refresh the result after the subscribe and will inform all the components which are using this "value" to update its value, including the ng-container. The container would allow rendering the child component now, which will guarantee that the results are not null when the child will be going through its life cycle.

msanford
  • 11,803
  • 11
  • 66
  • 93
Samy Sammour
  • 2,298
  • 2
  • 31
  • 66
1

if you are sure that your service gets data successfully so this will work :

in the html of your parent component add the quotes :

<app-childComponent [dataNeeded]="results"></app-childComponent>

in your child component , you will check changes of your Inputusing the OnCh:

ngOnChanges(changes: SimpleChanges) {   
   for (let propName in changes) {
      // when your @Input value is changed  
      if(propName === "dataNeeded"){
          console.log(dataNeeded);
      }
   }
}

Hope this would help :)

Mohamed Ali RACHID
  • 3,245
  • 11
  • 22
0

Why not using the Observable with the async pipe. If you want to console-log that value use a setter. The async pipe will also take care about unsubscribing.

results: Observable<any[]>;
ngOnInit() {
  this.results = this.http.get('url');
}

In the HTML

<app-childComponent [dataNeeded]="results | async"></app-childComponent>

And in your child component

@Input('dataNeeded') 
set dataNeeded(val: any[]) {
  console.log(val);
}
Michael Warneke
  • 253
  • 1
  • 7