So in HTML I can do something this:
<input type="file" id="upload" accept="text" multiple/>
Then I can access the files uploaded in JavaScript like this whenever the input changes:
document.getElementById('upload').onchange = function(){
const uFiles = this.files;
console.log(uFiles);
}
How would I go about doing that with ReactJS? So far, I've tried using the same approach I would use for HTML and JavaScript but I get the response that uFiles is undefined rather than a FileList object.
In my React Render:
<input onChange={this.doFunc} id="upload" type="file" accept="text" multiple />
In my React class:
doFunc = () => {
const uFiles = this.files;
console.log(uFiles);
}
I think you have to use event.
doFunc = e => {
const uFiles = e.target.files;
console.log(uFiles);
}
function handleUploadChange(e)
{
const file = e.target.files[0];
if ( !file )
{
return;
}
const reader = new FileReader();
reader.readAsBinaryString(file);
reader.onload = () => {
console.log(reader.result);
console.log(file.type);
};
reader.onerror = function () {
console.log("error on load image");
};
}
Related
I have a file input like this in html
<input type='file' id='textin'></input>
How Do I Get The Contents Of The .txt File Uploaded?
You can do this via FileReader.
function previewFile() {
const content = document.querySelector('.content');
const [file] = document.querySelector('input[type=file]').files;
const reader = new FileReader();
reader.addEventListener("load", () => {
// this will then display a text file
content.innerText = reader.result;
}, false);
if (file) {
reader.readAsText(file);
}
}
<input type="file" onchange="previewFile()" id="textin"><br>
<p class="content"></p>
This input element allows to take multiple images, for example if i select 2 images i get: FileList {0: File, 1: File, length: 2}. Then if i select again for example 1 image i get another FileList: FileList {0: File, length: 1}. There's a chance to push this new image to the first FileList? And it's possible to remove an image of the FileList by his index? Thanks in advance.
function handleFileSelect(evt) {
var files = evt.target.files; // FileList object
console.log(files);
for (var i = 0; i < files.length; i++) {
console.log(files[i]);
}
// Loop through the FileList and render image files as thumbnails.
for (var i = 0, f; f = files[i]; i++) {
if (!f.type.match('image.*')) {
continue;
}
let reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
// Render thumbnail.
var span = document.createElement('span');
span.innerHTML = ['<img class="thumb" src="', e.target.result,
'" title="', escape(theFile.name), '"/>'].join('');
document.getElementById('list').insertBefore(span, null);
};
})(f);
reader.readAsDataURL(f);
}
}
document.getElementById('files').addEventListener('change', handleFileSelect, false);
.thumb {
height: 75px;
border: 1px solid #000;
margin: 10px 5px 0 0;
}
<input type="file" id="files" name="files[]" multiple />
<output id="list"></output>
You are selecting only a single file 3 times.
To get multiple files you need to select them in a single call from the file-picker.
It will depend on the OS, but on my macOS I can do so by pressing the cmd key (probably ctrl on other OSes) while clicking on the items I want to select.
This is the way you can achieve your desired result using FormData.
You can change the code to achieve your desired look and functionality.
In summary what the following code does:
Creates a new FormData instance
Accepts files from file input
Appends the file to a field named file-${index} field of FormData created in step 1
Creates a FileReader instance for each File
The FileReader reads the file content and returns data: URL representing the file's data as a base64 encoded string.
Creates a span element and appends an img element to it with the fileContent of step 5 as src
Attaches the click listener to the span so when the user clicks an image the corresponding file will be removed from FormData of step 1 and the span will be removed from DOM
The FormData will be sent to the backend as a request body using Fetch API when the user clicks the submit files button using the sendFiles function as click handler.
you can see the list of files attached to FormData with their corrponding form field name and original filename under sunbmit button as a ul generated using listFiles function
const formData = new FormData();
// to be used for files field names of FormData
let index = 0;
// for listing current files
const listFiles = () => {
const list = document.createElement("ul");
Array.from(formData.entries()).forEach((entry) => {
const item = document.createElement("li");
item.innerHTML = entry[0] + ": " + entry[1].name;
list.appendChild(item);
});
document.querySelector("#fileList").innerHTML = list.innerHTML;
};
// for sending files to the backend
const sendFiles = () => {
fetch("/upload/path", {
body: formData,
method: "POST",
})
.then((response) => response.json()) // If the response is in JSON format
.then((data) => {
console.log(data);
})
.catch((error) => {
console.error(error);
});
};
// for outputting fileReader output and file for FormData
// it needs to be async because of async nature of fileReader onload event so we can keep FormData and FileReader in sync using index
const readFile = (file) => {
return new Promise((resolve, reject) => {
const fileReader = new FileReader();
fileReader.onload = (event) => {
const theFile = event.target;
return resolve([file, theFile]);
};
fileReader.readAsDataURL(file);
});
};
const handleFileSelect = async (event) => {
var files = event.target.files;
for (const file of files) {
if (file.type.match("image.*")) {
const [fileData, theFile] = await readFile(file);
const id = `file-${index}`;
formData.append(id, fileData);
const span = document.createElement("span");
const img = document.createElement("img");
img.src = theFile.result;
img.alt = "Image thumb";
img.title = escape(fileData.name);
img.className = "thumb";
span.appendChild(img);
// for removing the thumbnail and its linked file from FormData
span.addEventListener("click", () => {
formData.delete(id);
// listing current files appended to FormData after removing this thumbnail
listFiles();
span.remove();
});
index++;
document.getElementById("list").insertBefore(span, null);
}
}
// list files after adding new file/files
listFiles();
};
document.getElementById("files").addEventListener("change", handleFileSelect, false);
.thumb {
height: 75px;
border: 1px solid #000;
margin: 10px 5px 0 0;
}
<input type="file" id="files" name="files[]" multiple />
<br />
<h3>click on images to remove them</h3>
<output id="list"></output>
<br /><br /><br />
<button onclick="sendFiles()">submit Files</button>
<ul id="fileList"></ul>
example of How to upload a file using Fetch for refrence.
I am trying to make an audio file converter that lets a user submit a file. Then uses JavaScripts Web Audio API to convert the pitch and stretch the file. I have gotten as far as uploading the file, use file reader to onload a function that stretches and converts the pitch. Now I am trying to export that file with the changes and I can right now only download the original file but not with the changes. I dont know how to assign file = buffer because it's from another class. How should I got by making this happen?
convertFile () {
var fileInput = document.getElementById('audio-file')
var ctx = new AudioContext()
var convertFiles = document.getElementById('convert_button')
//load audio file listener
convertFiles.addEventListener("click", function() {
if (fileInput.files[0] == undefined) {
console.log("no file found")
return false
}
var reader1 = new FileReader()
reader1.onload = function(ev) {
ctx.decodeAudioData(ev.target.result). then(function(buffer){
var soundSource = ctx.createBufferSource()
soundSource.buffer = buffer
// create the stretch
soundSource.playbackRate.linearRampToValueAtTime(0.0185, ctx.currentTime)
//connect source
soundSource.connect(ctx.destination)
// convert pitch
var pitchChange = ctx.createBiquadFilter()
pitchChange.type = 'highpass'
pitchChange.frequency.value = 432
pitchChange.connect(ctx.destination)
})
}
reader1.readAsArrayBuffer(fileInput.files[0])
})
let file = fileInput.files[0]
let url = URL.createObjectURL(file)
let link = document.createElement('a')
link.href = url
link.download = file.name
link.click()
link = null
URL.revokeObjectURL(url)
}
render() {
return (
<div className="sec2">
<input type="file" id="audio-file" accept="audio/mpeg, audio/ogg, audio/*" name="file" onChange={this.uploadFile} />
<button type="button" id="convert_button" onClick={this.convertFile}>Convert to 432Hz</button>
<download onClick={this.downloadFile}>Download File</download>
</div>
)
}
}
export default ConverterSec2
I started looking into this... I fixed a couple issues such as the audio file being loaded twice. However this is work in progress answer... I haven't figure out the saving part yet.
class ConverterSec2 extends React.Component {
uploadFile = ({ target: { files } }) => {
console.log(files[0])
let data = new FormData()
data.append('file', files[0])
}
convertFile () {
var fileInput = document.getElementById('audio-file')
var ctx = new AudioContext()
var convertFiles = document.getElementById('convert_button')
//load audio file listener
if (fileInput.files[0] == undefined) {
console.log("no file found")
return false
}
var soundSource = ctx.createBufferSource();
var reader1 = new FileReader()
reader1.onload = function(ev) {
ctx.decodeAudioData(ev.target.result).then(function(buffer){
soundSource.buffer = buffer
// create the stretch
soundSource.playbackRate.linearRampToValueAtTime(0.0185, ctx.currentTime)
//connect source
soundSource.connect(ctx.destination)
// convert pitch
var pitchChange = ctx.createBiquadFilter()
pitchChange.type = 'highpass'
pitchChange.frequency.value = 432
pitchChange.connect(ctx.destination)
})
}
reader1.readAsArrayBuffer(fileInput.files[0]);
}
downloadFile() {
let fileInput = document.getElementById('audio-file')
let file = fileInput.files[0]
let url = URL.createObjectURL(file)
let link = document.createElement('a')
link.href = url
link.download = file.name
link.click()
link = null
URL.revokeObjectURL(url)
}
render() {
return (
<div className="sec2">
<input type="file" id="audio-file" accept="audio/mpeg, audio/ogg, audio/*" name="file" onChange={this.uploadFile} />
<button type="button" id="convert_button" onClick={this.convertFile}>Convert to 432Hz</button>
<button onClick={this.downloadFile}>Download File</button>
</div>
)
}
}
Live Demo
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?
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.
Edit:
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>
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);
}
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);
}
}
[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>
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)
}
}
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.
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" />
I have a html code like this:
<input type="file" id="up" />
<input type="submit" id="btn" />
And I have a JSON file like this:
{
"name": "John",
"family": "Smith"
}
And a simple JavaScript function:
alert_data(name, family)
{
alert('Name : ' + name + ', Family : '+ family)
}
Now I want to call alert_data() with name and family that stored in JSON file which uploaded using my HTML input.
Is there any way to use an HTML5 file reader or something else?
I'm not using server-side programming, all of them are client-side.
You will need an HTML5 browser, but this is possible.
(function(){
function onChange(event) {
var reader = new FileReader();
reader.onload = onReaderLoad;
reader.readAsText(event.target.files[0]);
}
function onReaderLoad(event){
console.log(event.target.result);
var obj = JSON.parse(event.target.result);
alert_data(obj.name, obj.family);
}
function alert_data(name, family){
alert('Name : ' + name + ', Family : ' + family);
}
document.getElementById('file').addEventListener('change', onChange);
}());
<input id="file" type="file" />
<p>Select a file with the following format.</p>
<pre>
{
"name": "testName",
"family": "testFamily"
}
</pre>
Since all answers seem unnecessarily complex, here's a simple async function that returns the file contents as an Object:
async function parseJsonFile(file) {
return new Promise((resolve, reject) => {
const fileReader = new FileReader()
fileReader.onload = event => resolve(JSON.parse(event.target.result))
fileReader.onerror = error => reject(error)
fileReader.readAsText(file)
})
}
const object = await parseJsonFile(file)
Here's a shorthand version of Sam Greenhalghs answer that works for me.
$(document).on('change', '.file-upload-button', function(event) {
var reader = new FileReader();
reader.onload = function(event) {
var jsonObj = JSON.parse(event.target.result);
alert(jsonObj.name);
}
reader.readAsText(event.target.files[0]);
});
<input class='file-upload-button' type="file" />
Yep! It can be done with HTML5 FileReader. And it's actually pretty simple.
Save the json as a .js file and load it in my example
{
"name": "John",
"family": "Smith"
}
This is where the magic happens:
$("#up").change(function(event){
var uploadedFile = event.target.files[0];
if(uploadedFile.type !== "text/javascript" && uploadedFile.type !== "application/x-javascript") {
alert("Wrong file type == " + uploadedFile.type);
return false;
}
if (uploadedFile) {
var readFile = new FileReader();
readFile.onload = function(e) {
var contents = e.target.result;
var json = JSON.parse(contents);
alert_data(json);
};
readFile.readAsText(uploadedFile);
} else {
console.log("Failed to load file");
}
});
function alert_data(json)
{
alert('Name : ' + json.name + ', Family : '+ json.family)
}
Fiddle link with this code: http://jsfiddle.net/thomas_kingo/dfej7p3r/3/
(The uploadedFile.type check is only tested in Chrome and firefox)