1

I'm trying to create a multiple images upload form and I have a problem with the uploaded images order. They don't upload by the selection I've made, but by the file size. I guess the problem is that because uploadImage in for doesn't wait for the other. I tried changing it to await uploadImage(files[index], 1); but now it gives error await is only valid in async functions and the top level bodies of modules.

const uploadImage = async (file, id) => {
    const fileReader = new FileReader();

    if(file) {
        fileReader.readAsDataURL(file);

        fileReader.onload = () => {
            let img = new Image();

            img.src = fileReader.result;

            img.onload = () => {
                let canvas = document.createElement("canvas");

                const MAX_WIDTH = 1000;
                const MAX_HEIGHT = 1500;

                let width = img.width;
                let height = img.height;

                if(width > height) {
                    if(width > MAX_WIDTH) {
                        height *= MAX_WIDTH / width;
                        width = MAX_WIDTH;
                    }
                }
                else {
                    if(height > MAX_HEIGHT) {
                        width *= MAX_HEIGHT / height;
                        height = MAX_HEIGHT;
                    }
                }

                canvas.width = width;
                canvas.height = height;

                let ctx = canvas.getContext("2d");

                ctx.drawImage(img, 0, 0, width, height);

                const base64Str = canvas.toDataURL("image/jpeg", 90);

                if(id == 0) {
                    return base64Str;
                }
                else {
                    document.getElementById("product_photo_" + id + "_result").innerHTML += '<img src="' + base64Str + '" class="img-thumbnail m-2 product_photo_' + id + '_base64" style="height: 50px;" />';
                }
            }
        };
    }
};

document.getElementById("product_photo_1").addEventListener("change", (event) => {
    let files = document.getElementById("product_photo_1").files;

    for(let index = 0; index <= files.length; index++) {
        uploadImage(files[index], 1);
    }
});

document.getElementById("product_photo_2").addEventListener("change", (event) => {
    let files = document.getElementById("product_photo_2").files;

    for(let index = 0; index <= files.length; index++) {
        uploadImage(files[index], 2);
    }
});
  • "await is only valid in async functions and the top level bodies of modules" — Is there something unclear about the error message? Make the arrow function you call `uploadImage` from an `async` function. – Quentin Jun 23 '23 at 08:58
  • `const uploadImage = async (file, id) => {` — Making that function `async` is pointless as you don't use `await` inside it. See the duplicate about converting the `onload` callback function into a promise. – Quentin Jun 23 '23 at 08:59

1 Answers1

0

You should add async to your functions where you want to use await:

document.getElementById("product_photo_1").addEventListener("change", async (event) => {
    let files = document.getElementById("product_photo_1").files;

    for(let index = 0; index <= files.length; index++) {
        await uploadImage(files[index], 1);
    }
});

More about await:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await

Also you should return a valid promise from you uploadImage function:

const uploadImage = (file, id) => {

    if (!file) {
        return Promise.reject(new Error('No file provided'));
    }

    const fileReader = new FileReader();

    fileReader.readAsDataURL(file);

    return new Promise((resolve, reject) => {

        fileReader.onerror = reject;

        fileReader.onload = () => {
            let img = new Image();

            img.src = fileReader.result;

            img.onload = () => {

                let canvas = document.createElement("canvas");

                const MAX_WIDTH = 1000;
                const MAX_HEIGHT = 1500;

                let width = img.width;
                let height = img.height;

                if (width > height) {
                    if (width > MAX_WIDTH) {
                        height *= MAX_WIDTH / width;
                        width = MAX_WIDTH;
                    }
                }
                else {
                    if (height > MAX_HEIGHT) {
                        width *= MAX_HEIGHT / height;
                        height = MAX_HEIGHT;
                    }
                }

                canvas.width = width;
                canvas.height = height;

                let ctx = canvas.getContext("2d");

                ctx.drawImage(img, 0, 0, width, height);

                const base64Str = canvas.toDataURL("image/jpeg", 90);

                if (id) {
                    document.getElementById("product_photo_" + id + "_result").innerHTML += '<img src="' + base64Str + '" class="img-thumbnail m-2 product_photo_' + id + '_base64" style="height: 50px;" />';
                }
                resolve(base64Str);

            }
        }
    });

};
Alexander Nenashev
  • 8,775
  • 2
  • 6
  • 17