How to pass Async data return from an Observable from Child to Parent component in Angular

2.6k views Asked by At

I am trying to pass Async data from child to parent component. But in here console.log(this.values) inside ngAfterViewInit() gives an empty value in parent component html page load. But if i click apply button in child component it will emit the event an console.log(this.values); inside getValues($event) method prints.

This is my parent component .ts file

name = 'ViewUI';
@ViewChild('ChildValues', { static: false }) childReference: ChildComponent;

 ngAfterViewInit() {
  this.values = this.childReference.this.responseValues;
  console.log(this.values);
  mapResponse(this.values);
}

In here `mapResponse(this.values)` method runs before coming data from `this.values` from child component to parent.
getValues($event) {
  this.values = $event;
  console.log(this.values);
  this.apply();
}

This is my parent component .html file

<app-child #ChildValues (getEvent)=" getValues($event)" [name]="name"></app-child>

This is my child component .html file.

<button (click)="applyResponses()" mat-raised-button>
  Apply
</button>

This is my Child component .ts file

  export class ChildComponent implements OnInit {
      responseValues = {
            names: [], ages: []
        };
      @Output() getEvent = new EventEmitter < any > ();
      @Input() name: string;
    
      ngOnInit() {
        this.getNames();
        this.getAges();
        console.log(this.name);
      }
    
     getNames() {
       this.apiService.getnames(Id).subscribe((names) => {
         this.responseValues.names = [names[0].name];
        });
     }
    
     getAges() {
       this.apiService.getages(Id).subscribe((ages) => {
         this.responseValues.ages = [ages[0].age];
        });
     }
      applyResponses() {
        this.getEvent.emit(this.responseValues);
        console.log(this.responseValues);
      }
    }

How can i get data from child to parent component on parent page load?

1

There are 1 answers

8
Eliseo On

why not, in ngOnInit in child, you define a new emiter?

@Output()dataReceived= new EventEmitter < any > ();

ngOnInit()
{
   forkJoin(this.getNames(),this.getAges()).subscribe(([names,ages]:[any[],any[]])=>{
       this.dataReceived.emit({names:names,ages:ages})
   })
}

And in your parent?

<app-child (dataReceived)="storeData($event)"></app-child>
storeData(data:any)
{
    console.log(data.names,data.ages)
}

Update it's an answer about a question in comment, Remember that you are not sure that you get the data. To check it we are going to "simulate" a slow response from server. for this import delay from 'rxjs/operators'

import {delay} from 'rxjs/operators'

And change the subscripcion by

this.apiService.getages(Id).pipe(
  delay(10000))
  .subscribe((ages) => {
     this.responseValues.ages = [ages[0].age];
    });

If you click the button before 10 seconds you has not the data