0
votes

I am emitting array of URLimages from child component to parent using EventEmitter.

Child's emitter:

@Output() images  = new EventEmitter<string[]>();

Parent's html:

<app-file-upload (images)="onLoadedImages($event)"></app-file-upload>

where <app-file-upload> is the child.

Parent's OnLoadedImages() function:

  onLoadedImages(images: string[]) {
    console.log(images);
    console.log(images[0]);
  }

Console output: image of console output

Why does images[0] give undefined when in the console output I can see it has the data and how can I access images: string[] data?

Edit:

@Colby Hunter As an answer to comment, here's content of child:

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

  loadedImagesAsURL = [];
  @Output() images  = new EventEmitter<string[]>();

  constructor() {
  }

  ngOnInit() {
  }

  onFileSelected(event) {
    const filesList = event.target.files;
    for (const file of filesList) {
      const reader = new FileReader();
      reader.onload = (e: any) => {
        this.loadedImagesAsURL.push(e.target.result);
      };
      reader.readAsDataURL(file);
    }
    this.images.emit(this.loadedImagesAsURL);
  }
}
<div class="text-center" *ngIf="loadedImagesAsURL.length>0" style="height: 300px; overflow: auto;">
  <span *ngFor="let image of loadedImagesAsURL">
    <img style="width: 100%;" height="400" src="{{image}}">
  </span>
</div>
<div>
  <input type="file" multiple (change)="onFileSelected($event)" style="display: none;" #fileUpload>
  <button type="button" class="btn btn-secondary" (click)="fileUpload.click()">Wybierz zdjęcia</button>
</div>
1
What does your child component look like in terms of ts and HTML files?Colby Hunter

1 Answers

2
votes

Browser's console does lazy evaluation. Try doing:

console.log(JSON.stringify(images));
console.log(images[0]);

you will see it as an empty array.

In your case by the time you manually click onto the console log of "images", the file gets loaded and you see the content.

Since you need to read all the files and do a final emission, make all the file read events as an observable, emit your array once all the Obsevables are complete.

public onFileSelected(event): void {
    let loadenedObs = this._createFileReaderObs(event);
    forkJoin(...loadenedObs).subscribe(() => {
        // all the files are read, emit the array now.
        this.images.emit(this.loadedImagesAsURL);
   })
}

private _createFileReaderObs(event): [] {
    let obsArr = [];
    const filesList = event.target.files;
    for (const file of filesList) {
      const reader = new FileReader();

      const loadenedEventObs = fromEvent(reader, 'loadend').pipe(
            tap(() => {
                this.loadedImagesAsURL.push(reader.result);
            }),
            take(1)      // take one event to complete the Observable
        );

      obsArr.push(loadenedEventObs);    // create an array of loadened observables.
      reader.readAsDataURL(file);
    }
    return obsArr;
}