Reputation: 1381
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?
Upvotes: 30
Views: 56004
Reputation: 21
This allows a JSON file to be uploaded through a button press like this answer. The createJsonUploader
function creates its own file input.
The getUploadedJson
function is based on this answer's code using the Blob API. The code uses IDs that are compatible with the top answer's js fiddle.
document.getElementById('import').onclick = createJsonUploader;
function createJsonUploader() {
const inputFileElement = document.createElement('input');
inputFileElement.setAttribute('type', 'file');
inputFileElement.setAttribute('accept', '.json');
inputFileElement.onchange = function() {
getUploadedJson(this, displayText)
};
document.body.appendChild(inputFileElement);
inputFileElement.click();
inputFileElement.remove();
}
function getUploadedJson(fileInput, callback) {
var files = fileInput.files;
if (files.length <= 0) return;
files[0].text().then(function(text) {
console.log(text);
var result = JSON.parse(text);
callback(result);
});
}
function displayText(result) {
var formatted = JSON.stringify(result, null, 2);
document.getElementById('result').value = formatted;
}
Upvotes: 0
Reputation: 1533
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.
Upvotes: 1
Reputation: 1535
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); } }
Upvotes: 7
Reputation: 41
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>
Upvotes: 4
Reputation: 9531
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" />
Upvotes: 0
Reputation: 21
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)
}
}
Upvotes: 2
Reputation: 158
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")
}
});
}
}),
Upvotes: 0
Reputation: 5625
Without server side code, your best approach may be to provide a textarea
element for the user to copy/paste the JSON into, and then parse it using JSON.parse
.
You could even go as far as to use something like Ace Editor to provide syntax highlighting for JSON - you can see it in action on the Ace Editor Kitchen Sink Demo - select JSON from the dropdown list in the top left.
Turns out I was wrong. Here is a fiddle demonstrating the FileReader in use, which is exactly what you need:
https://jsfiddle.net/Ln37kqc0/
Here is the code:
Javascript:
document.getElementById('import').onclick = function() {
var files = document.getElementById('selectFiles').files;
console.log(files);
if (files.length <= 0) {
return false;
}
var fr = new FileReader();
fr.onload = function(e) {
console.log(e);
var result = JSON.parse(e.target.result);
var formatted = JSON.stringify(result, null, 2);
document.getElementById('result').value = formatted;
}
fr.readAsText(files.item(0));
};
HTML:
<input type="file" id="selectFiles" value="Import" /><br />
<button id="import">Import</button>
<textarea id="result"></textarea>
Upvotes: 43
Reputation: 1381
I have got a way to use the uploaded json file, here is the way i found.
$("#inputFile").change(function(e) {
onChange(e);
});
function onChange(event) {
var reader = new FileReader();
reader.onload = onReaderLoad;
reader.readAsText(event.target.files[0]);
}
function onReaderLoad(event){
//alert(event.target.result);
var obj = JSON.parse(event.target.result);
alert(obj);
}
Upvotes: 13