Uploading a JSON file and using it

Viewed 44686

How can I upload a JSON file on some click on a button on my web page say "import", and use it to store in a variable to use and update it using JavaScript.

I have gone through the other posts but could not find any answer.

I am saving the JSON variable using this function:

function save(filename, data){

    if(!data) {
        alert('error : No data')
        return;
    }

    if(typeof data === "object"){
        data = JSON.stringify(data, undefined, 4)
    }

    var blob = new Blob([data], {type: 'text/json'}),
        e    = document.createEvent('MouseEvents'),
        a    = document.createElement('a')

    a.download = filename
    a.href = window.URL.createObjectURL(blob)
    a.dataset.downloadurl =  ['text/json', a.download, a.href].join(':')
    e.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)
    a.dispatchEvent(e)
 }

This is working fine and it downloads the file on clicking another button say "export". How upload this file back and make a JSON variable of this file data?

8 Answers

Basic upload File:

    <input id="contentFile" type="file" accept="application/json" />
  document.getElementById('contentFile').onchange = function(evt) {
        try {
            let files = evt.target.files;
            if (!files.length) {
                alert('No file selected!');
                return;
            }
            let file = files[0];
            let reader = new FileReader();
            const self = this;
            reader.onload = (event) => {
                console.log('FILE CONTENT', event.target.result);
            };
            reader.readAsText(file);
        } catch (err) {
            console.error(err);
        }
    }

Try this, works perfect

handleUploadFile = async(doc) => {
  let file = doc.target.files[0]
  let reader = new FileReader(file)

  // await reader.readAsDataURL(file)

  reader.readAsText(file)

  reader.onload = async(e) => {

    let aaa = e.target.result

    let content = await JSON.parse(aaa)
    console.log(content)

  }
}

[2021] Promise based approach

As mentioned here, you can make use of the newer blob api to easily get the file's value via:

await blob.text()

const getJsonUpload = () =>
  new Promise(resolve => {
    const inputFileElement = document.createElement('input')
    inputFileElement.setAttribute('type', 'file')
    inputFileElement.setAttribute('multiple', 'true')
    inputFileElement.setAttribute('accept', '.json')
    
    inputFileElement.addEventListener(
      'change',
      async (event) => {
        const { files } = event.target
        if (!files) {
          return
        }

        const filePromises = [...files].map(file => file.text())

        resolve(await Promise.all(filePromises))
      },
      false,
    )
    inputFileElement.click()
  })


document.getElementById('upload-button').onclick = async () => {
    const jsonFiles = await getJsonUpload()
  console.log({jsonFiles})
}
<button id="upload-button">
Upload
</button>

You may want to add the draggable option

Firs create your HTML

<div class="drag" id="drag_area">
        <input class="box_file disabled" type="file" name="files[]" id="file" data-multiple-caption="{count} files selected" multiple />
        <label for="file"><strong>Choose save file</strong><span class="box__dragndrop"> or drag it here</span>.</label>
</div>

Than write out your JS

$("#drag_area").on('drag dragstart dragend dragover dragenter dragleave drop', function (e) {
    e.preventDefault();
    e.stopPropagation();
})
.on('dragover dragenter', function () {
    $("#drag_area").addClass('dr_active');
    // this is needed if you wish to style your drag area on drag events
})
.on('dragleave dragend drop', function () {
    $("#drag_area").removeClass('dr_active');
    // this is needed if you wish to style your drag area on drag events
})
.on('drop', function (e) {
    let droppedFiles = e.originalEvent.dataTransfer.files;
    let reader = new FileReader()
    reader.readAsDataURL(droppedFiles[0])
    reader.onloadend = function () {
    $.ajax({
        url: reader.result,
        success: function (data) {
          console.log(JSON.parse(data)); // This is your JSON
        },
        error: function (request, error) {
            cliLog(2, "Upload", "Cant upload save file")
        }
    });
}
}),

I'd made a more general approach with support to customize upload button title and callback when load is done:

function uploadJson(id, callback) {
    document.getElementById(id).onchange = function(evt) {
        try {
            let files = evt.target.files;
            if (!files.length) {
                alert('No file selected!');
                return;
            }
            let file = files[0];
            let reader = new FileReader();
            const self = this;
            reader.onload = (event) => {
                callback(event.target.result);
            };
            reader.readAsText(file);
        } catch (err) {
            console.error(err);
        }
    }
}

uploadJson('importJson', function (json) {
    console.log(json);
});
<button onclick="document.getElementById('importJson').click()">import json</button>
<input id="importJson" value="import json" type="file" accept="application/json" style="display:none" />

With the newer Blob API, the current top answer can be simplified by skipping the FileReader:

document.getElementById('import').onclick = function() {
  var files = document.getElementById('selectFiles').files;
  console.log(files);
  if (files.length <= 0) {
    return false;
  }
  files[0].text().then(function(text) { 
    console.log(text);
    var result = JSON.parse(text);
    var formatted = JSON.stringify(result, null, 2);
    document.getElementById('result').value = formatted;
  })
};

To explain the code a little: files[0] itself is a File object, which inherits from Blob, so files[0].text() is an asynchronous function that reads the content of the file into a string.

Related