Reputation: 654
I'm trying to declare an array of object in Typescript. However, I'm facing error retrieving the object. Below is my code. Image shows output of this.attachments
.
info: Info[];
if (this.attachments.length > 0) {
this.previewInfo(this.attachments);
}
previewInfo(infos) {
this.info = [];
for (let i = 0; i < infos.length; i++) {
let reader = new FileReader();
reader.onload = (e: any) => {
var temp = new Info;
temp = {
id: i,
url: e.target.result,
message: ""
}
this.info.push(temp);
}
reader.readAsDataURL(infos[i]);
}
}
The result I get contains an empty array in front which looks like this.
[]0: {id: 0, url: "test1", message: ""}
1: {id: 1, url: "test2", message: ""}
2: {id: 2, url: "test3", message: ""}
This causes undefined when I try to retrieve them using
this.info[0]
If I skip the second line which is this.info=[]
, I'm getting an error which says
Cannot read property '0' of undefined
Did I declare it wrongly? How can I retrieve info by index?
Upvotes: 0
Views: 8088
Reputation: 73347
Akber Iqbal's answer works, but their solution does not guarantee that the files are in the same order as the attachments
array, so
here is a solution, if there is an importance of that the info
items are in the same order as the files in the attachments
array. You are looking for the first item, so maybe it is important. We can use Promises and async/await
:
async onFileSelected(event) {
this.attachments = [];
this.info = [];
for (let index = 0; index < event.target.files.length; index++) {
let file = event.target.files[index];
this.attachments.push(file);
}
if (this.attachments.length > 0) {
for (let i = 0; i < this.attachments.length; i++) {
try {
// wait that the file has been processed before moving on to next file
let temp = await this.readFile(this.attachments[i], i);
this.info.push(temp)
if (this.attachments.length === this.info.length) {
// here we have the first item after all files has been completed
console.log(this.info[0])
}
} catch (err) {
console.log(err);
}
}
}
}
And processing the file from the for
-loop here, by passing the file and the index and returning the temp file:
readFile(file, i) {
return new Promise((resolve, reject) => {
let reader = new FileReader();
reader.onload = (e: any) => {
let temp = {
id: i,
url: e.target.result,
message: file.name, // for testing I put the file name as message
}
resolve(temp);
};
reader.readAsDataURL(file)
})
}
DEMO: StackBlitz
Upvotes: 1
Reputation: 15031
The issue is of asynchronous calls;
When your loop finishes and these 2 lines are executed... by that time the reader.onload
hadn't finished and therefore this.info.push(temp);
didn't run and you see a blank in your console when you run these 2 lines below:
console.log(this.info);
console.log(this.info[0]); //this is what i need
What we need to do is to let the loop finish, and in the very last iteration (where i == infos.length - 1
) of the loop... we print the values on the console and get the correct result;
relevant TS:
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
//Variable declaration
attachments = [];
info = [];
onFileSelected(event) {
this.attachments = [];
for (var index = 0; index < event.target.files.length; index++) {
var file = event.target.files[index];
this.attachments.push(file);
}
if (this.attachments.length > 0) {
this.previewInfo(this.attachments);
console.log('caller', this.attachments);
}
}
previewInfo(infos) {
this.info = [];
if (infos) {
for (let i = 0; i < infos.length; i++) {
let reader = new FileReader();
reader.onload = (e: any) => {
let temp = {
id: i,
url: e.target.result,
message: "",
}
//console.log(temp);
if (i == infos.length - 1) {
this.pusher(temp, true);
} else {
this.pusher(temp, false);
}
//this.info.push(temp, function(){ console.log('pushed'); } );
}
reader.readAsDataURL(infos[i]);
}
console.log('empty: ', this.info);
console.log('empty: ', this.info[0]); //this is what i need
}
}
pusher(tempFile, lastFile) {
this.info.push(tempFile);
if (lastFile == true) {
console.log('Correct Filled: ', this.info.length);
console.log('Correct Filled: ', this.info[0]); //this is what i need
}
}
}
complete working stackblitz here
Upvotes: 0