using react js I need multiple image upload with preview I tried with below code is not working it showing me error in console
Uncaught DOMException: Failed to set the 'value' property on
'HTMLInputElement': This input element accepts a filename, which may
only be programmatically set to the empty string.
uploadImage(e){
var numFiles = e.target.files.length;
for (var i = 0, numFiles = e.target.files.length; i < numFiles; i++){
var file = e.target.files[i];
if(!file.type.match('image'))
continue;
var reader = new FileReader();
reader.onload = function(e) {
setOfImages.push({
fileName:file.name,
image:e.target.result.split(',')[1]
});
for(var j = 0; j<setOfImages.length; j++) {
$('.placeholder-blk').prepend('<div class="image-placeholder"><img src="data:image/jpeg;base64,'+ setOfImages[j].image +'" /></div>');
}
console.log(setOfImages);
}
reader.readAsDataURL(file);
}
}
<input type="file" name="image-uploder" id="image-uploder" className="file-loader" onChange={this.uploadImage.bind(this)} multiple />
Did you try adding the value to the state and populate the name from the state.
Something like
<input type="file" name={this.state.setOfImages} id="image-uploder" className="file-loader" onChange={this.uploadImage.bind(this)} multiple />
and inside your function populate the state.
this.setState({setOfImages: JSON.stringify(setOfImages)})
something like this.
export class Demo extends React.Component{
constructor(props){
super(props)
this.state = {
setOfImages : []
}
}
setOfImages(event){
event.preventDefault();
this.setState({
setOfImages: ["hello", "hi"]
})
}
render(){
return (
<div>
<input value={this.state.setOfImages}/>
<button onClick={this.setOfImages.bind(this)}/>
</div>
)
}
}
Now first the input will be populated with empty array . When you click the button the state will change by setting the setOfImages = ["hello", "hi"] and making the input value set to those values.
This makes no sense $('.placeholder-blk').remove(); then subsequently try to prepend to that? It's gone.
And here only the first file?
var file = e.target.files[0];
Did you mean to process the files
var numFiles = e.target.files.length;
for (var i = 0, numFiles = e.target.files.length; i < numFiles; i++)
{ var file = e.target.files[i]; .. }
Ref here how to do it raw: developer.mozilla.org/en-US/docs/
Related
I am trying to add property to file object. I am adding property like this (I am using Vue):
<input type="file" id="fileUpload" name="file" #change="setToUploadStatus" multiple>
setToUploadStatus method:
setToUploadStatus (event) {
let files = event.target.files
Array.from(files).forEach((file) => {
let id = this.randomString(10)
file.id = id
this.uploadStatus.push({
id: id,
name: file.name,
uploading: false,
uploaded: false
})
}
this.uploadFile(files)
}
uploadFile method:
async uploadFile (files) {
for (const file of files) {
// Upload file with axios
}
}
randomString method:
randomString (length) {
let text = ''
let possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
for (var i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length))
}
return text
}
My problem is it's not adding id property always. Sometime it's adding sometime not. Specially when many files are selected. Here is a log https://prnt.sc/kxsqhi
What am I doing wrong? Please help!
Converted to a snippet here:
setToUploadStatus(event) {
let files = event.target.files
Array.from(files).forEach((file) => {
let id = this.randomString(10)
file.id = id
this.uploadStatus.push({
id: id,
name: file.name,
uploading: false,
uploaded: false
})
}
this.uploadFile(files)
}
async uploadFile(files) {
for (const file of files) {
// Upload file with axios
}
}
randomString(length) {
let text = ''
let possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
for (var i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length))
}
return text
}
<input type="file" id="fileUpload" name="file" #change="setToUploadStatus" multiple>
First, from the code you've given there is nothing wrong with it. Perhaps the issue is coming from somewhere else.
Second, I see you want to give a unique id to every file. Generating a random string is fine, but there is still a possibility that two random strings will be the same. So here is a simple way to go about that.
new Vue({
el: "#app",
data: {},
methods: {
updateFile(event) {
let files = event.target.files
let uid = 0;
Array.from(files).forEach(file => {
file.id = ++uid;
console.log(file);
});
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<input type="file" multiple #input="updateFile" />
</div>
This implementation is simple.
Here is the JSFiddle Link: https://jsfiddle.net/clintonyeb/3qreb1L9/
With the following input field, the user submits one or multiple HTML files.
<input type="file" id="inputfield" accept="text/html" multiple/>
<div id="get-files">Get Files</div>
When get-files is clicked, how can I get the content of each file on the input field and mess with each file content using the fileReader API?
I tried the following but receive no errors or content.
$("#get-files").on("click", function() { getFilesContent(); });
function getFilesContent() {
var pages = $("#inputfield")[0].files;
// get files data
for (var i = 0; i < pages.length; i++) {
var reader = new FileReader();
reader.onload = (function() {
return function(e) {
console.log($("#inputfield")[0].result);
}
});
reader.readAsText(pages[i]);
}
}
Try this instead
function getFilesContent() {
var pages = $("#inputfield")[0].files;
for (let i = 0; i < pages.length; i++) {
let reader = new FileReader();
reader.onload = function() {
console.log(reader.result);
}
reader.readAsText(pages[i]);
}
}
reader.result contains your HTML data.
my problem is when I select the multiple images it displaying correct, and I am storing this in one array, from that array I need to get the image name. right now it's working but in setOfImages array all image name is same. i need to take the image URL also when i put that setOfImages array in map function that URL are get repeating this are two problems I am facing if not clear put console.log(setOfImages) and console.log(imageUrl),
imagetrigger(e){
var setOfImages =[], imageUrl=[];
for (var i = 0; i < e.target.files.length; i++){
var file = e.target.files[i];
if(!file.type.match('image'))
continue;
var reader = new FileReader();
reader.onload = function(e){
setOfImages.push({
fileName:file.name,
image:e.target.result.split(',')[1]
});
$('.image').remove();
for(var j = 0; j<setOfImages.length; j++) {
$('.placeholder').prepend('<div class="image"><img src="data:image/jpeg;base64,'+ setOfImages[j].image +'" /></div>');
}
setOfImages.map(function(){
imageUrl.push(el.fileName);
})
console.log(imageUrl)
}
reader.readAsDataURL(file);
}
}
Just add parameter el to your map.
setOfImages.map(function(){
imageUrl.push(el.fileName);
})
Change like this.
setOfImages.map(function(el){
imageUrl.push(el.fileName);
})
I'm working on a simple script for my site to upload images. I have a multiple file input <input type = 'file' name = 'files[]' id = 'hiddenFile' multiple> that is being triggered by a div click. When I queue the files, I want to be able to delete one. I know I can loop through the $('#hiddenFile').val() and splice to get the name out but I'm having an issue with figuring out the file name. When I assign the file to a new img container, how do I get the name? I've tried console.log(f.name) and a few variations but it returns an undefined error. Here are my scripts. I think I'm pretty close but this is something I'm learning as I go. Thanks!
function readURL(input) {
var files = $('#hiddenFile')[0].files; //where files would be the id of your multi file input
//or use document.getElementById('files').files;
for (var i = 0, f; f = files[i]; i++) {
var reader = new FileReader();
reader.onload = function (e) {
console.log(f.name); //how can I get the
//file name here to add it to the image as an attribute?
$("<img src = '"+e.target.result+"' class = 'addedImg'>").appendTo("#imgBox");
};
reader.readAsDataURL(f);
}
}
$(document).ready(function(){
$(document).on('click', '#addBtn', function(e){
e.preventDefault();
$('#hiddenFile').click();
});
});
Try using change event , defining f within an IIFE , setting title attribute value to f.name
$(document).ready(function() {
$(document).on('click', '#addBtn', function(e) {
e.preventDefault();
$('#hiddenFile').click();
});
$("#hiddenFile").change(function(event) {
var files = this.files;
var i = 0,
len = files.length;
(function readFile(n) {
var reader = new FileReader();
var f = files[n];
reader.onload = function(e) {
console.log(f.name);
$("<img src=" + e.target.result + " class=addedImg title=" + f.name + ">")
.appendTo("#imgBox");
// if `n` is less than `len` ,
// call `readFile` with incremented `n` as parameter
if (n < len -1) readFile(++n)
};
reader.readAsDataURL(f); // `f` : current `File` object
}(i)); // `i` : `n` within immediately invoked function expression
})
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<div id="addBtn">click</div>
<input type="file" style="display:none" id="hiddenFile" multiple />
<div id="imgBox"></div>
The FileReader object itself does not have access to the file name. You get the file name while you're iterating over the files list as you are doing in your for loop.
var reader = new FileReader();
reader.onload = function (e) {
//update image src or something
};
for (var i = 0, f; f = files[i]; i++) {
reader.readAsDataURL(f); //updates image src or something
//additional method to do something with file name goes here
}
And if you really want to have one method that does those two things in the for loop, then you can wrap it all up in a closure like #ebidel does in his answer here - Get filename after filereader asynchronously loaded a file#answer-12547471.
I have form with the following form:
<form>
...
<input type="file" multiple="multiple" id="images" />
<a id="add">Add</a>
...
<input type="submit" value="Submit" />
</form>
The add element's click event is then wired up like so:
var images = [];
$("#add").click(function() {
var files = $("#images")[0].files;
for (var i = 0; i < files.length; i++) {
images.push[files[i];
}
$("#images").val("");
});
This allows me to add the images from multiple locations. Now I need to send the files back to the server. I found the following question:
Passing path to uploaded file from HTML5 drag & drop to input field
Which seems to be similar. Therefore I used the following to wire up an event when the form is submitted:
var form = $("form");
form.submit(function() {
for (var i = 0; i < images.length; i++) {
var reader = new FileReader();
reader.onload = function(e) {
$("<input>").attr({ type: "hidden", name: "images[]" }).val(e.target.result).appendTo(form);
};
reader.readAsDataURL(images[i]);
}
});
Finally on the server I have the following code:
print_r($_POST);
print_r($_FILES);
However neither collection contains an item for the images submitted. I was wondering what I am doing wrong? Thanks
Alright, I think your problem here is being caused by the FileReader's load event handler, which appends those data URLs to the form, being called after the form is submitted to the server.
You could solve this problem, and do away with the superfluous images variable and submit event handler by adding these items to the form in the click handler for the Add link. You can also use this opportunity to do a little client side validation, preventing duplicate data URLs from being uploaded to the server, and even to add a preview/remove option for the selected images.
Furthermore, you could do away with the Add link by replacing its click handler with a change handler attached to your file input.
Edit (nfplee):
var images = [];
$("#add").click(function() {
var files = $("#images")[0].files;
for (var i = 0; i < files.length; i++) {
var reader = new FileReader();
reader.onload = (function(file) {
return function(e) {
images.push({ name: file.name, file: e.target.result });
};
})(files[i]);
reader.readAsDataURL(files[i]);
}
$("#images").val("");
});
var form = $("form");
form.submit(function() {
for (var i = 0; i < images.length; i++) {
$("<input>").attr({ type: "hidden",
name: "images[" + i + "][name]" }).val(images[i].name).appendTo(form);
$("<input>").attr({ type: "hidden",
name: "images[" + i + "][file]" }).val(images[i].file).appendTo(form);
}
});