Home > OS >  Upload and Parse multiple JSON files in javascript and vuejs
Upload and Parse multiple JSON files in javascript and vuejs

Time:06-24

I am trying to upload and save multiple JSON files. previously for uploading and saving a single JSON file I was doing this:

<input type="file" id="file" ref="fileSelect"  @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 was saving the json file in this.data

Now I want to upload and save multiple JSON files similarly and save them in this.data So I updated the above code as follows (I thought I can loop and append the file data):

<input multiple type="file" id="file" ref="fileSelect"  @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]);}

    }

But this is not working as intended, it is only appending the file selected last multiple times (and the 0th index is null, so for example if I select file1.json , file2.json, file3.json in this.data 0 is null and 1,2 index are data from file3.json. What am I doing wrong?

My current complete code:

<input multiple type="file" id="file" ref="fileSelect"  @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]);
          }
   }

CodePudding user response:

There's really nothing Vue or TypeScript specific in your question, so I'll attempt to answer with plain old JavaScript. I've included a runnable code snippet.

In a nutshell, whenever the selected files change:

  • Create a single FileReader instead of one per selected file.
  • Attach a single load event listener, and obtain the FileReader's result (the file content).
  • Read each file, one at a time, waiting for each file to be loaded and read prior to reading the next file.

Were it me, I would make a function to read a file and resolve with the file's content. You could then call that function from your showFiles method, and await the result of each file.

Here's a runnable example in raw JavaScript. Note that inputFile corresponds to your fileSelect reference, and the results array corresponds to your data array (which, BTW, should be an array not an object). Also, I've wired up the change event listener in the JS code, but it's the same as the @change listener in your template.

(function() {
  'use strict'

  const inputFile = document.getElementById('inputFile')

  // Holds the contents of each selected file.
  const results = []

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

    // New set of results each time.
    results.splice(0)

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

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

  /**
   * Read a file asynchronously and resolve with the contents.
   * 
   * @param {FileReader} reader - A FileReader instance that will read `file`
   * as text.
   * @param {File} file - A selected File instance.
   */
  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>

  • Related