0
votes

Parent component displays the data correctly but it is not sending the asynchronously populated data to the child component

I am new to Angular and I am following its documentation from this page: https://angular.io/guide/component-interaction I am able to read file details into a parent component asynchronously using an Angular service. When I display the file details from the parent component, I can see that the file was read correctly. When I am passing the data using @Output() variable and receiving it in the child component using @Input, I am getting empty data as if the child component received the Input synchronously but not asynchronously.

Here's the service:

import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import {inFile} from '../Classes/inFile';
@Injectable({
  providedIn: 'root'
})
export class AddFilesService {
  inFileObj = new inFile();
  inFiles:any = [];
  constructor(private http:HttpClient) { }
  uploadFiles(event){
    const files = event.target.files;
    for (let i=0; i<= files.length-1 ; i++){
      const file = files[i];
      const fileName = file.name;     
      const reader = new FileReader();
       //ASYNCHRONOUS FILE READ
        reader.onload = () => { 
            this.inFileObj.name = fileName;
            this.inFileObj.size = file.size;                   
        };            
        reader.readAsArrayBuffer(file);
      }      
      this.inFiles.push(this.inFileObj);    
    return of(this.inFiles);
  } 
}

Here's the parent component component that takes a file input and displays file name and file size:

import { Component, OnInit, Output } from '@angular/core';
import {AddFilesService} from '../../services/add-files.service';
@Component({
  selector: 'app-input-form',
  templateUrl: './input-form.component.html',
  styleUrls: ['./input-form.component.css']
})
export class InputFormComponent implements OnInit {
  inFiles:any = [];
  @Output() uploadedFileDetails:string;
  constructor(private addFilesService: AddFilesService) { }
  ngOnInit() {
  }
  fileUpload(event) : void {
   this.addFilesService.uploadFiles(event).subscribe(
      data => {
        //THIS WORKS
        this.inFiles = data;
        //THIS DOES NOT WORK
        this.uploadedFileDetails = data;
      },
      error =>{
        console.log(error);
      }
    );
  }
}

Here's the parent HTML template:

`<input type="file"  (change)="fileUpload($event)" multiple>
 <table>
 <tbody>
  <tr *ngFor = "let inFile of inFiles">
   <td>Name from Parent: {{inFile.name}}</td>
   <td>Size from Parent: {{inFile.size}}</td>
  </tr>
 </tbody>
</table>`

Output from parent component:

Name from Parent: Test.txt Size from Parent: 57

Here's the child component:

import { Component, OnInit, Input } from '@angular/core';
@Component({
 selector: 'app-map',
 templateUrl: './map.component.html',
 styleUrls: ['./map.component.css'],
})
export class MapComponent implements OnInit { 
  @Input() uploadedFileDetails:string;  
  constructor() {}
  ngOnInit() {        
  }
}

Here's the child HTML which has no output:

 `<table>
  <tbody>
   <tr *ngFor = "let inFile of uploadedFileDetails">
    <td>Name from Child: {{inFile.name}}</td>
    <td>Size from Child: {{inFile.size}}</td>
   </tr>
 </tbody>
 </table>`
1
where do you put <app-map [uploadedFileDetails]="uploadedFileDetails"><app-map> in your parent html? - Fateme Fazli

1 Answers

0
votes

You have 2 problems:

First you don't use Output()in the parent components only in the child components to Emit and Event with data for example to the parent data to the child.

And you are missing this line

<app-map [uploadedFileDetails]="uploadedFileDetails"><app-map>

Where [uploadedFileDetails] is your @Input variable in the child component