The issue arises from the fact that the onload
handler is executing asynchronously while you are constantly overwriting the reader
variable within the synchronous for
loop. As the for
loop operates synchronously, the onload
callback will only run in the subsequent cycle of the event loop. Due to variables declared with var
having function scope, the reader
variable in the handler function will solely reference the last image, leading to only the final image being processed.
Given your use of typescript
, it's presumed that you can utilize the const
/let
keywords. To rectify your code, consider declaring the reader
variable as const
or let
. Variables declared with const
or let
have block scope, creating new blocks on each cycle of the for
loop, preventing them from overriding each other and existing independently within their respective blocks.
fileUpload(event: Event) {
const self = this;
this.imageUploadInp = event.target as HTMLInputElement;
this.imageUploadInp.addEventListener("change", function () {
for (let i = 0; i < self.imageUploadInp.files.length; i++) {
const reader = new FileReader(); // declared as `const`
reader.onload = function () {
if (reader.result != undefined) {
self.user.imgUrls = reader.result.toString();
console.log(self.user.imgUrls);
}
}
reader.readAsDataURL(self.imageUploadInp.files[i]);
}
});
}
I've also changed the declaration of the i
variable to let
within the for
loop. This decision ensures that any use of the var i
variable inside the onload
handler won't face the same fate as the var reader
, which becomes equal to
self.imageUploadInp.files.length - 1
after the completion of the
for
loop.
If circumstances prevent you from using let
/const
, another approach involves creating unique functions for each cycle of the for
loop to encapsulate var reader
within different function scopes:
fileUpload(event: Event) {
const self = this;
this.imageUploadInp = event.target as HTMLInputElement;
this.imageUploadInp.addEventListener("change", function () {
for (var i = 0; i < self.imageUploadInp.files.length; i++) {
(function () { // creating different function scopes on each cycle
var reader = new FileReader();
reader.onload = function () {
if (reader.result != undefined) {
self.user.imgUrls = reader.result.toString();
console.log(self.user.imgUrls);
}
}
reader.readAsDataURL(self.imageUploadInp.files[i]);
}());
}
});
}
In this updated version, I've utilized the IIFE pattern to isolate each reader
variable created in the for
loop within its distinct function scope.