0
votes

When I try to pass ASYNC data from parent to child component, I'm getting undefined message.

Because of ASYNC data, I suppose data coming from parent is not yet bound at OnInit.

In parent.component.html :

<my-child [childdata]="parentdata"></my-child>

In parent.component.ts :

interface SpotBB {
    id: number;
    name: string;
}
...
export class ParentComponent implements OnInit {
  parentdata: Observable<SpotBB[]>;
  ...
  ngOnInit() {
    this.parentdata = this.spotsservice.getSpots();
    // Call a service - Data stored in Firestore
  }

In child.component.html :

<button (click)="mycheck()">TEST</button>
<div *ngFor="let spot of childdata | async" >    
    {{ spot.id }} --- {{ spot.name }}     <!-- Works fine -->
</div>

In child.component.ts :

interface SpotBB {
    id: number;
    name: string;
}
...
export class ChildComponent implements OnInit {
  @Input() childdata: Observable<SpotBB[]>;
  copydata: Observable<SpotBB[]>;
  ...
  mycheck() {
    alert(JSON.stringify(this.copydata));   // --> !!! undefined !!!
  }
  ngOnInit() {
    this.copydata = this.childdata;  // COPY DATA NOT WORKING
  }
2
have you tried by console in the child component's ngOnInit like this console.log(this.childdate)Pardeep Jain
First of all, Observable do not fetch data if you don't subscribe it. log the this.childdata on OnInit. Let me know it is undefined or not.Ritwick Dey
console.log(this.childdate) (in OnInit) is undefined.Michel_
add *ngIf condition. <my-child *ngIf=" parentdata" [childdata]="parentdata"></my-child>. It will load child component after getting value from parent component.Dharan

2 Answers

3
votes

You can implement several options to get it wokring:

1. Listen for changing @Input in your child component using ngOnChanges:

// child component
export class ChildComponent implements OnInit {
  @Input() childdata;
  ngOnChanges(changes: SimpleChanges) {
    // on loading you can access childdata
    console.log(changes.childdata.currentValue);
  }

2. Using set in child component for childdata:

// child component
export class ChildComponent implements OnInit {
  private _childdata;
  @Input() set childdata(value) {
    this._childdata = value;
  }


  // get method for childdata (for *nfFor in template)
  get childdata() {
    return this._childdata;
  }

3. Make child component available (if it is acceptable) only after parentdata will be available:

parent component html:

<my-child *ngIf="parentDataLoaded" [childdata]="parentdata"></my-child>

In parent.component.ts :

interface SpotBB {
  id: number;
  name: string;
}
...
export class ParentComponent implements OnInit {
  parentdata: Observable<SpotBB[]>;
  parentDataLoaded: false;
  ...
  ngOnInit() {
    this.spotsservice.getSpots()
      .subscribe(res => {
         // here is your successful results
         this.parentdata = res;
         this.parentDataLoaded = true;
      });
  }

For all options, I'm guessing to subscribe to getSpots, receive parentdata in your parent component and assign to this.parentdata:

// parent component
ngOnInit() {
  this.spotsservice.getSpots()
    .subscribe(res => {
      // here is your successful results
      this.parentdata = res;
    });
 }

 // child component html
 // *ngIf needs only if listening for changing
 // of childdata in child component
 <div *ngIf="childdata">
   <div *ngFor="let spot of childdata" >    
    {{ spot.id }} --- {{ spot.name }}     <!-- Works fine -->
   </div>
 </div>
0
votes

Instead of @Input() childData to @Input() set childData will work. This will get the childData to be refreshed on change.