Submit the request when the fileReader's onload event is triggered

Do you have any suggestions on how to improve my fileReader for uploading images? I am currently facing an issue where multiple requests are being sent to the server when there are more than 1 image due to a for loop. How can I modify my code to address this issue?


        for (let file of selectedFiles) {
            const fileName = file.name;
            const reader = new FileReader();
            reader.readAsArrayBuffer(file);
            reader.onload = () => {
                const image = reader.result as any;
                var base64 = btoa(
                    new Uint8Array(image)
                        .reduce((data, byte) => data + String.fromCharCode(byte), '')
                );
                imageArray.push({ fileName: fileName, content: base64 });
                console.log(imageArray);
                this.service.create(this.finalData).subscribe({
                    next: data => {
                    console.log(data);
                    this.openSnackBar("Success", 'x');
                },
                error: error => {
                    console.error('There was an error!', error);
                }
            })
        }
    }
    

Answer №1

If you have a lot of asynchronous tasks to handle simultaneously, utilizing promises can save you a significant amount of time and effort.

To start, create a function that takes a file and returns a promise that resolves to the desired data.

Let's define FileData here for clarity on how things will unfold.

type FileData = {
    fileName: string;
    content: string; // base64 encoded
};

const getFileData = (file) => {
    const fileName = file.name;
    
    const promise = new Promise(
        (res, rej) => {
            const reader = new FileReader();
            reader.readAsArrayBuffer(file);
            reader.onload = () => {
                const image = reader.result as any;
                var base64 = btoa(
                    new Uint8Array(image)
                      .reduce((data, byte) => data + String.fromCharCode(byte), '')
                  );
                const data: FileData = { fileName: fileName, content: base64 };
                res(data)
            };
    });

    return promise;
};

Next, execute your loop but utilize the function to retrieve your data and consolidate the results into an array.

const promises = [];
for (let file of selectedFiles) {
    promises.push(getFileData(promises));
};

Then utilize Promise.all to execute another function once all promises are fulfilled and data is available.

Promise.all(promises).then((dataArray: FileData[]) => {

    // Proceed to work with dataArray and upload all the data in the array at once

});

With that being said, consider modifying the server to support a standard multipart MIME formatted request and use FormData for uploading the data instead of manually converting everything to base64.

const data = new FormData(document.getElementById('myForm');
const responsePromise = fetch('/url', { method: "POST", body: data });

… this approach requires less effort than the previous method! It achieves the same outcome, just in a different format.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Angular 2: Implementing service functions on button click using the (click) event

Is it possible to call a function from my service when clicking on an element in the HTML returned from an HTTP call? Here is the HTML snippet: <a (click)="SellingVarietiesService.goToVarietyDetails(3)">Test</a> The function I want to call i ...

Choosing the open status of an HTML list

Is there a way to determine which containers in a list are currently open and which ones are still closed? Currently, I am utilizing the slideDown(), slideDown(), and addClass functions on divs with the specific class="section_hdl_aktiv". However, I want ...

Changing the value of a textarea in Angular forms using JavaScript

Having trouble with Angular forms? Try this: document.querySelector(TEXTAREA_SELECTOR).value = "some text" Methods like .title, .name, or .innerText don't seem to work. Consider trying these: document.querySelector(TEXTAREA_SELECTOR).dispa ...

const error = new TypeError(`${calculateRelativePath(cwd, fileName)}: Skipping emission of file`);

Hey there! I have a typescript code snippet that looks like this: import { getConnection } from "typeorm"; import { GraphQLClient } from "graphql-request"; import got from "got"; import database from "./utils/database&quo ...

Created a notification for when the user clicks the back button, but now looking to remove it upon form submission

My survey is lengthy and I don't want users to accidentally lose their data by clicking the back button. Currently, I have an alert that warns them about potential data loss, but the alert also pops up when they submit the form. Is there a way to disa ...

Dynamic <figcaption> that adjusts to different screen sizes with smooth animations

My first WordPress theme is almost complete and I'm excited to share it: The responsive image grid on the homepage is giving me some trouble. When I shrink the browser window, the images don't scale properly. The grid works fine without the JS ( ...

How to retrieve data from a nested object in Angular templates

I am working with a "post" object that has an "author" property, linking each post to the author who created it. The "author" property is a nested "user" object with a "name" property. My goal is to access the "name" of the user associated with a specifi ...

I require the JSON data to be displayed in an array format

I am looking to convert a JSON object into a JSON array in Laravel. Currently, I am receiving JSON data in object format. $category = new Categories; return Response::json(array( 'error' => false, 'category' => $category- ...

Implementing a filter on retrieved data from an API in a React application

I'm retrieving information from this Api After fetching the data, I need to check if the gender is Male in order to display a Male Icon. How can I perform this check on the Api data and return some HTML data like an img tag or something to show the i ...

The benefits of a modular design in a React and TypeScript library

Following a tutorial on creating a library with React, Typescript, and rollup, I successfully managed to get everything working. However, as my project grows with additional features, I'm looking to have modular exports similar to what is seen in redu ...

Error in jQuery: Null property causing TypeError when reading 'text'

Issue: I have a modal form that is loaded via an ajax call. Inside the modal, there is a span element containing an email address. I am trying to capture the value of this span element using JavaScript. Currently, I have a button click event that triggers ...

Convert Angular 2 Observable to a regular value

Currently using version 6.3 of NGX Data Table, I am facing an issue where I cannot bind to an observable collection. How can I convert an Angular Observable Collection into a standard non-observable Array? Below is the code snippet for the service: priva ...

Vue-Select Runs into Issue Generating Choices from an Array

As a novice in the world of Vue and Nuxt JS, I am currently immersed in learning and developing a simple web application with Nuxt JS. One specific challenge I am facing is creating a Vue Select option where I pass an array and have the options represent t ...

I am looking to modify the background color of characters in a text box once the characters in a textarea exceed 150 characters

Currently, I am utilizing event.data to capture the text inputted into this particular HTML textbox. My intention is to change the background color to red based on that input. However, when using the style attribute on event.data, I encounter an error. It& ...

I'm having trouble saving the session, what could be the issue?

Hey there, I've created a form where users can sign up. Once the user fills in all the details and clicks submit, an Ajax request sends the form data to the database. If this process happens without any errors, a hidden div containing payment buttons ...

Angular 2 isn't triggering the custom validator for every keypress

I have implemented a custom validator for Reactive forms in Angular 2. However, I am facing an issue where my function is only validating the first key press in the text field. Ideally, the custom function should validate each key press. Can someone please ...

Issue: npm encountered an error due to writing after reaching the end

I've encountered a problem while trying to install Cordova and Ionic. Due to what appears to be a corrupted installation, I had to uninstall NodeJS - Cordova - Ionic. After re-installing NodeJS successfully, the trouble began when running the pop ...

Can you explain the functionality of express-async-handler?

Hello, I'm trying to understand the purpose of express-async-handler. I came across it in a repository I was exploring. According to the documentation, express-async-handler is a simple middleware designed to handle exceptions within asynchronous exp ...

Tips for resolving errors in Angular controls

Setting custom errors in Angular is straightforward with this code snippet: this.form.controls['field'].setErrors({same:true}); However, the process for removing custom errors is not as obvious. Does anyone know how to accomplish this? Are ther ...

Display PickerIOS when a button is clicked in a React Native application

I am a beginner with the react framework and I'm trying to implement a PickerIOS component on button click. However, I'm having trouble understanding how to call other classes upon an event. I found this code snippet on the React Native site: v ...