Uploading and parsing multiple JSON files using JavaScript and Vue.js

I have been working on uploading and saving multiple JSON files. In the past, I had successfully implemented code for uploading and saving a single JSON file using the following approach:

<input type="file" id="file" ref="fileSelect" class="custom-file-input" @change="showfiles" /> 
showfiles() {
        let files = (this.$refs.fileSelect as HTMLInputElement).files
        var reader = new FileReader();
        reader.onload = () => { this.data = JSON.parse(reader.result as string); }
        reader.readAsText(files![0]);
    }

I used to save the JSON file data in this.data.

Now, my goal is to upload and save multiple JSON files in a similar manner and store them in this.data. So, I made some updates to the existing code thinking that I could loop through and append the file data:

<input multiple type="file" id="file" ref="fileSelect" class="custom-file-input" @change="showfiles" />  
showfiles() {
        let files = (this.$refs.fileSelect as HTMLInputElement).files
        
        for(let i=0;i<files!.length;i++){   
          var reader = new FileReader();       
          reader.onload = () => { this.data[i] = JSON.parse(reader.result as string); }
          reader.readAsText(files![i]);}

    }

However, this updated code is not functioning as expected. It seems to be appending only the last selected file multiple times (with the 0th index being null). For instance, if I select file1.json, file2.json, file3.json, then in this.data - 0 is null and indexes 1 and 2 contain the data from file3.json. What might I be doing wrong?

Here is my current complete code:

<input multiple type="file" id="file" ref="fileSelect" class="custom-file-input" @change="showfiles" />  
<script lang='ts'>
import { defineComponent } from "vue"

export default defineComponent({
  name: 'HomeView',
  props: [],
  data(){
    return{
      data:{}
      
    };
  },
  methods: {
    showfiles() {
      this.data={}
      let files = (this.$refs.fileSelect as HTMLInputElement).files
         
       for(let i=0;i<files!.length;i++){       
           var reader = new FileReader();     
           reader.onload = () => { this.data[i] = JSON.parse(reader.result as string);}
           reader.readAsText(files![i]);
          }
   }

Answer №1

Your question doesn't seem to require any Vue or TypeScript-specific solutions, so I'll provide an answer using plain JavaScript. Below is a code snippet that you can run to achieve the desired functionality.

Essentially, the approach involves:

  • Utilizing a single FileReader instance instead of creating one for each selected file.
  • Adding a single event listener for the load event and getting the file content from the result property of the FileReader.
  • Reading each file sequentially to ensure that each file is fully loaded before moving on to the next file.

If it were up to me, I would create a function to read a file and return its content. This function could then be called within your showFiles method using await for each file.

Below is a working example implemented in pure JavaScript. Note that the inputFile variable corresponds to your fileSelect reference, and the results array corresponds to your data array (which should be an array rather than an object). The event handling in the JS code mirrors the @change listener in your template.

(function() {
  'use strict'

  const inputFile = document.getElementById('inputFile')

  // Array to store file contents.
  const results = []

  inputFile.addEventListener('change', async e => {
    const files = e.target.files
    const reader = new FileReader()

    // Clear results array for fresh data.
    results.splice(0)

    for (const file of files)
      results.push(await readFile(reader, file))

    // Do something with the file contents.
    console.log(results)
  })

  /**
   * Read a file asynchronously and resolve with the content.
   * 
   * @param {FileReader} reader - Instance of FileReader to read `file` as text.
   * @param {File} file - Selected File object.
   */
  function readFile(reader, file) {
    const deferredResult = new Promise(resolve => {
      reader.addEventListener('load', function getResult() {
        resolve(reader.result)
        reader.removeEventListener('load', getResult)
      })
    })

    reader.readAsText(file)

    return deferredResult
  }
})()
<!doctype html>

<html>
  <head>
  </head>

  <body>
    <input multiple type="file" id="inputFile" accept=".json">
  </body>
</html>

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 does not assign the ng-invalid-class to the input

In order to register custom validation methods for custom form elements, we use extra directives as shown below: <ng-form name="validatorTestForm"> <our-input-directive name="validatorTest" ng-model="ourModel"/> ...

Update the database with the new values and display them in an HTML table

I am working with a table that looks like the one below: <script> $("#edit").hide(); // Initially hide the edit table $("#update").click(function() { $("#edit").toggle(); $("#shown").toggle(); ...

Have you ever wondered why the expression `Number(new Boolean(false))` always returns `0

In the case of Boolean(new Boolean(...)) === true, it is because new Boolean(...) is treated as an object. However, why does Number(new Boolean(false)) === 0 (+new Boolean(false) === 0) and Number(new Boolean(true)) === 1? Instead of resulting in NaN. Wh ...

How to generate a collection of identical services in AngularJS

One of the features I have is a Service that can be added by a user, either one or multiple services. There is a button available for users to add a new Service: <button type="button" class="btn btn-success" ng-click="addService()"> <span cl ...

What is the best way to format a string into a specific pattern within an Angular application

In my Angular component, I have 4 fields: customerName, startDate, and startTime. Additionally, I have a fourth field that is a textarea where the user can see the message that will be sent via email or SMS. Within my component, I have defined a string as ...

Highlighting a row upon being clicked

How can I implement a feature in my HTML page that highlights a row when selected by changing the row color to #DFDFDF? If another row is selected, I would like the previously selected row to return to its original color and the newly selected row to be h ...

Recording the details of an Angular project through the utilization of Compodoc

I am currently in the process of documenting my Angular + Typescript application using Compodoc. To install Compodoc, I utilized npm and executed the following command: 'npm install -g compodoc'. And included "compodoc": "./node_modules/ ...

What criteria should I consider when selecting a JavaScript dependency framework?

When it comes to installing dependencies, how do I determine whether to use NPM or Bower? For example, what distinguishes npm install requirejs --save-dev from bower install requirejs --save-dev? Is there a recommended method, or any guidelines for makin ...

How to Force Redirect to HTTPS on Elastic Beanstalk with Node.js and Express

Seeking assistance in setting up a site to enforce HTTPS (redirecting from HTTP). Our HTTPS is configured through AWS Elastic Beanstalk, but currently both HTTP and HTTPS are accessible. After reviewing various resources, such as this one, I attempted the ...

Avoiding conflicts between banners, text, and images for HTML/CSS design

I'm having an issue with the banner I created for my project. It seems to be overlapping with text and images, hiding behind them. How can I fix this? Unfortunately, I can't post the link to my project here due to other files present. The specif ...

Is there a way to generate a fresh array by filtering an array of objects based on a single value?

I am currently working with an array of objects: const dummyLinkRows = [ { id: 'entity:link/1:en', categories: [ { name: 'Human Resources' }, { name: 'Social' } ], nam ...

The output from a JavaScript function differs from that of an Excel formula

Currently, I am facing the challenge of converting an Excel spreadsheet into an HTML/CSS/JavaScript page. One major obstacle is translating the formula 100*(50+15)*(100%+100%*50%) from Excel to JavaScript. Unfortunately, the % sign has a different interpre ...

Issue with Fragment Shader not appearing in ThreeJS

Seeking assistance with threejs and shader implementation. I am encountering difficulties with displaying a shader, particularly with the variable "len" in the code. I suspect this variable is the root cause of the issue. The codepen link for reference: ht ...

What is the best MySQL data type for storing JavaScript code with PHP?

I am creating a platform that resembles jsfiddle, allowing users to store their JavaScript codes and retrieve them in an organized manner. I am unsure about which data type would be most suitable for saving the codes, or if storing them in text files wou ...

Encountering an issue with extending the MUI color palette, receiving a "reading 'dark'" error due to properties of undefined

Encountering an issue when trying to expand the MUI color palette—getting this error instead: Error: Cannot read properties of undefined (reading 'dark') Take a look at my theme.ts file below: const theme = createTheme({ palette: { pri ...

Executing child processes in the Mean Stack environment involves utilizing the `child_process`

I am working on a Mean application that utilizes nodejs, angularjs and expressjs. In my setup, the server is called from the angular controller like this: Angular Controller.js $http.post('/sample', $scope.sample).then(function (response) ...

What could be causing the malfunction of the map function, despite the code appearing to be correct?

I have encountered an issue in my React functional component where I am trying to display a list of notifications. The useEffect() function is being called to generate the "data" which should then be displayed on the page. The code seems to be running fine ...

Sending an object to a component and changing its properties to be mutable

Is there a way to pass a Contact object into my ContactDetailsComponent so that I can use the component for both displaying and editing the Contact? I attempted to pass the object as a Prop, but I'm struggling to edit it. Here is what I've tried ...

The shadows in Three Js are functioning correctly, although there are a few shadow lines visible below my model

I am currently in the process of modifying a three.js scene, despite having little experience with javascript and three.js. After successfully adding a shadow to my GLTF model, I noticed some yellow and red lines beneath the model that I cannot identify or ...

A more concise method to verify if something is undefined in JavaScript

Anyone have suggestions for a more concise idiom to use? const x = module || window; // Reference Error fallback Is there a shorter method to verify the presence of module? ...