Hi all i have code for multiple upload image, but i want only one image per upload. so I create the input file every time I clicked the upload button with the dynamic id. however I have problems checking whether the user chooses the file to upload or press the cancel button. because if the user pressed the cancel button I want to delete the input file I have created. for full sourcenya as below:
$(document).ready(function () {
$("#btnimg").click(function () {
//check input file id number
var counter = $("input[id^='upload']").length;
//add input file every btnimg clicked
var html = "<input type='file' id='upload_" + counter + "' style='display:none;'/>";
$("#result").append(html);
//trigger to dialog open file
var upload = $('#upload_' + counter);
upload.trigger('click');
upload.on('change', function () {
console.log('change fire...');
var inputFiles = this.files;
var inputFile = inputFiles[0];
var reader = new FileReader();
reader.onload = function (evt) {
var imghtml = "<img id='img_upload_" + counter + "' src='" + evt.target.result + "' width='50px;' height='50px;'/>";
$('#previewimage').append(imghtml);
};
reader.onerror = function (event) {
alert("something: " + event.target.error.code);
};
reader.readAsDataURL(inputFile);
});
//if file not selected or user press button cancel on open dialog
//upload.remove();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div id="result"></div>
<button id="btnimg">upload image</button>
<div id="previewimage">
</div>
</body>
thank you in advance,
You can check the .length of <input type="file"> element .files property to determine if a file is selected by user
That all sounds like an xy-problem to me.
I have not (yet) got a response from you about the why you want to do it, so I will base my answer on two probable situations:
If you want to keep track of the selected Files, in order to be able to do anything with them later (e.g send them through AJAX), then use a single <input>.
At every change event, you will store the new File in an Array, from where you will also be able to do something with later on:
(function() {
// this Array will hold our files, should be accessible to the final function 'doSomething'
var savedFiles = [];
var counter = 0;
var upload = $('#upload');
upload.on('change', onuploadchange);
$("#btnimg").click(function routeClick() {
upload.trigger('click');
});
$('#endbtn').click(function doSomething() {
console.log(savedFiles);
});
function onuploadchange() {
var inputFiles = this.files;
var inputFile = inputFiles[0];
if (!inputFile) { return; } // no File ? return
savedFiles.push(inputFile); // save this File
// don't use a FileReader here, useless and counter-productive
var url = URL.createObjectURL(inputFile);
var imghtml = "<img id='img_upload_" + counter + "' src='" + url + "' width='50px;' height='50px;'/>";
$('#previewimage').append(imghtml);
$('#endbtn').removeAttr('disabled');
}
})();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="result">
<!-- A single input to save them all-->
<input type='file' id='upload' style='display:none;' />
</div>
<button id="btnimg">upload image</button>
<div id="previewimage">
</div>
<button id="endbtn" disabled>do something with saved files</button>
If, for an obscure reason, you absolutely need to keep all the filled <input> elements in your document, then create a new one only if the last one is itself filled.
$(document).ready(function() {
$("#btnimg").click(function() {
// grab previous ones
var inputs = $("input[id^='upload']");
// get the last one we created
var last = inputs.last();
var counter = inputs.length;
console.log(counter);
var upload;
// if there is no input at all, or if the last one is already filled with a File
if (!last.length || last[0].files.length) {
console.log('create new input');
upload = makeNewInput();
} else {
// use the last one
upload = last;
}
//trigger to dialog open file
upload.trigger('click');
function makeNewInput(counter) {
var html = "<input type='file' id='upload_" + counter + "' style='display:none;'/>";
var el = $(html);
el.on('change', onuploadchange);
$('#result').append(el);
return el;
}
function onuploadchange() {
var inputFiles = this.files;
var inputFile = inputFiles[0];
var url = URL.createObjectURL(inputFile);
var imghtml = "<img id='img_upload_" + counter + "' src='" + url + "' width='50px;' height='50px;'/>";
$('#previewimage').append(imghtml);
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="result"></div>
<button id="btnimg">upload image</button>
<div id="previewimage">
</div>
Related
This question already has an answer here:
How to set file input value when dropping file on page? [duplicate]
(1 answer)
Closed 4 years ago.
I have a small HTML5 form where the user drops an image file, sees the preview, gets to know the dimensions of the image, fills an input element, and hits the button "Send" to dispatch it all (image and input text) through a POST request.
Problem is, the image data is not being sent together with the input data, even if the div and img elements have a name tag assigned to them. How can I accomplish that using the usual POST process?
Here is my code.
function removeDragData(e) {
if (e.dataTransfer.items) { // Use DataTransferItemList interface to remove the drag data
e.dataTransfer.items.clear();
} else { // Use DataTransfer interface to remove the drag data
e.dataTransfer.clearData();
}
}
function formatBytes(a,b) {
if (0 == a)
return '0 Bytes';
var c = 1024,
d = b || 2,
e = ['Bytes','KB','MB','GB','TB','PB','EB','ZB','YB'],
f = Math.floor(Math.log(a)/Math.log(c));
return parseFloat((a/Math.pow(c,f)).toFixed(d))+' '+e[f];
}
function getDim(img,tam) {
var infoW = img.naturalWidth;
var infoH = img.naturalHeight;
var info = document.getElementById('addDadoInfo');
info.innerHTML = 'Tamanho: ' + infoW + ' x ' + infoH + ' pixels (' + formatBytes(tam) + ')';
}
function drop(e,who) {
e.preventDefault(); // Prevent default behavior (Prevent file from being opened)
var i;
if (e.dataTransfer.items) { // Use DataTransferItemList interface to access the file(s)
for (i=0; i<e.dataTransfer.items.length; i++) {
if (e.dataTransfer.items[i].kind === 'file') { // If dropped items aren't files, reject them
var file = e.dataTransfer.items[i].getAsFile();
if (file.type.indexOf('image/') == 0 && file.size <= 2*1024*1024) {
// Process only the first image up to 2 MB
var img = document.createElement('img');
var tam = file.size;
img.file = file;
img.name = 'imgDImg';
img.style.maxWidth = '400px';
img.style.maxHeight = '300px';
while (who.firstChild) {
who.removeChild(who.firstChild); // removes the <p> element
}
who.appendChild(img);
var reader = new FileReader();
reader.onload = (function(aImg) {
return function(ev) {
aImg.src = ev.target.result;
setTimeout(getDim,500,aImg,tam);
};
})(img);
reader.readAsDataURL(file);
break;
//console.log('.A. file[' + i + '] = ' + file.name + '|' + file.type + '|' + file.size);
}
}
}
} else { // Use DataTransfer interface to access the file(s)
for (i=0; i<e.dataTransfer.files.length; i++) {
var file = e.dataTransfer.files[i];
console.log('.B. file[' + i + '] = ' + file.name + '|' + file.type + '|' + file.size);
}
}
removeDragData(e); // Pass event to removeDragData for cleanup
}
function dragOver(e) {
e.preventDefault(); // Prevent default behavior (Prevent file from being opened)
}
.addDado {
background-color:#DDD;
width:400px;
height:300px;
text-align:center;
}
<form id='frmAddDado' autocomplete='on' method='post' action='index.php'>
<div id='addDado1' name='addDado1' class='addDado' ondrop='drop(event,this)' ondragover='dragOver(event)'>
<p>Drop image here.</p>
</div>
<div id='addDadoInfo'>(No data selected.)</div>
<br>
<label for='txaDRef'>Reference</label><br>
<textarea id='txaDRef' name='txaDRef' cols=80 rows=5></textarea><br>
<br>
<input id='btnAddDado' type='submit' value='Add' disabled />
</form>
Well, this answer helped me to get it partially done, converting the image into base64 and attaching this to a hidden input. However, it's only 100% ok for PNG images. If the user tries to upload a JPG, there's no way it seems I can save the file as-is, i.e. without losing quality or increasing the file size.
So, I'm still looking for a better way to have both: thumbnail, dimensions and file size displayed and perfect file transfer.
EDIT
Digging more, I've found this answer, which does exactly what I needed!
A few modifications to the code above:
// in <form id='frmAddDado'>
<input id='fileIMG' name='fileIMG' type='file' style='display:none' />
// in function drop(e,who)
document.getElementById('fileIMG').files = e.dataTransfer.files;
am trying to show the image name also in multiple image upload.in case of single selection its working but in case of multiple selection image name Repeats. please check my fiddle. am also trying to show the image path
You just need to change:
Working Fiddle: https://jsfiddle.net/1kojL0pk/
var f = $('.trnsupload').prop("files")[0]['name'];
To
var f = $('.trnsupload').prop("files")[i]['name'];
// Full Code:
window.Transfer = function (input) {
if (input.files && input.files[0]) {
$(input.files).each(function (i) { // add index over here
var f = $('.trnsupload').prop("files")[i]['name']; // access file using i-th index
var reader = new FileReader();
reader.readAsDataURL(this);
reader.onload = function (e) {
$("#Viewer").append("<div class='imageContainer'><img onclick='changeIt(this)' class='thumb img-thumbnail' src='" + e.target.result + "'> <span class='MultiFile-title'>" + f + "</span> <span class='loader'><img src='../../Images/ajax-loader.gif' /></span> <span class='closeCover glyphicon glyphicon-remove'></span></div>");
}
});
}
}
I'm trying to create a form where I can have multiple file upload sections, where the user can upload multiple files.
That part, is reasonably straight forward. My problem comes from allowing the user to 'remove' a file from the upload list, before it's uploaded.
I've created a fiddle to illustrate
http://jsfiddle.net/alexjamesbrown/o62srbew/
I've got a simple row, that holds the <input type="file"
<div class="row files" id="files1">
<h2>Files 1</h2>
<span class="btn btn-default btn-file">
Browse <input type="file" name="files1" multiple />
</span>
<br />
<ul class="fileList"></ul>
</div>
then, so far, I've created a jquery plugin so it's re-usable:
$.fn.fileUploader = function (filesToUpload) {
this.closest(".files").change(function (evt) {
for (var i = 0; i < evt.target.files.length; i++) {
filesToUpload.push(evt.target.files[i]);
};
var output = [];
for (var i = 0, f; f = evt.target.files[i]; i++) {
var removeLink = "Remove";
output.push("<li><strong>", escape(f.name), "</strong> - ",
f.size, " bytes. ", removeLink, "</li> ");
}
$(this).children(".fileList")
.append(output.join(""));
});
};
I'm then initialising my very basic plugin like this:
var filesToUpload = [];
$("#files1").fileUploader(filesToUpload);
$("#files2").fileUploader(filesToUpload);
$("#uploadBtn").click(function (e) {
e.preventDefault();
});
As in this JSFiddle, I've added a class name .removeFile to the dynamically generated remove link; then use this class as a selector to pick up the one which is clicked and remove the parent li.
Updated:
JS:
// add .removeFile class to the li's element to pick them by this selector
var removeLink = "<a class=\"removeFile\" href=\"#\" data-fileid=\"" + i + "\">Remove</a>";
output.push("<li><strong>", escape(f.name), "</strong> - ",
f.size, " bytes. ", removeLink, "</li> ");
}
$(this).children(".fileList")
.append(output.join(""));
});
};
var filesToUpload = [];
$(document).on("click",".removeFile", function(e){
e.preventDefault();
var fileName = $(this).parent().children("strong").text();
// loop through the files array and check if the name of that file matches FileName
// and get the index of the match
for(i = 0; i < filesToUpload.length; ++ i){
if(filesToUpload[i].name == fileName){
//console.log("match at: " + i);
// remove the one element at the index where we get a match
filesToUpload.splice(i, 1);
}
}
//console.log(filesToUpload);
// remove the <li> element of the removed file from the page DOM
$(this).parent().remove();
});
You can un-comment the console.log() statements to see the result
I have an image upload script that creates a hidden div tag when an image is uploaded and should remove the image tag if somebody deletes the photo.
When somebody uploads it, it creates a tag like this:
<input type="hidden" id="hidden_image_1903180_620338339358jpg"
name="ad_image[]" value="image_1903180_620338339358.jpg">
The photo can be deleted with:
<a onclick="delete_media('image_1903180_620338339358jpg', 1, 1903180);">
Delete Photo</a>
The problem is what when somebody clicks delete, it doesn't remove the entire tag, it only removes the value like this:
<input type="hidden" id="hidden_image_1903180_620338339358jpg"
name="ad_image[]" value="">
How can I make it so the entire <div> ... </div> is removed?
The delete_media function is like this:
function delete_media_async(box_id, media_type, id) {
var file_name = document.getElementById('hidden_' + box_id).value;
var xmlHttp = GetXmlHttpObject();
if (xmlHttp == null) {
alert("Browser does not support HTTP Request");
return;
}
var url = relative_path + 'file.php';
var action = url + '?do=remove&file_name=' + file_name + '&id=' + id;
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4) {
var response = xmlHttp.responseText;
document.getElementById('box_' + box_id).innerHTML = '';
document.getElementById('box_' + box_id).className = 'thumbnail_display_empty';
document.getElementById('hidden_' + box_id).value = '';
var nb_uploads = document.getElementById('nb_uploads_' + media_type).value;
nb_uploads--;
document.getElementById('nb_uploads_' + media_type).value = nb_uploads;
document.getElementById('btn_upload_' + media_type).disabled = false;
document.getElementById('item_file_upload_' + media_type).disabled = false;
document.getElementById('item_file_url_' + media_type).disabled = false;
document.getElementById('item_file_embed_' + media_type).disabled = false;
}
};
xmlHttp.open("GET", action, true);
xmlHttp.send(null);
}
$('#hidden_' + box_id).remove() will remove the input field. If the input field is enclosed in a div and you want to remove that:
$('#hidden_' + box_id).parent().remove()
Edit: this is using jQuery
Assuming that your hidden input has a div as its parent, you could remove that div using this:
var hidden_input = document.getElementById('hidden_' + box_id);
var parent_div = hidden_input.parentNode;
var parent_of__parent_div = parent_div.parentNode;
// now remove the parent div:
parent_of__parent_div.removeChild( parent_div );
Insert that in your function and it should remove your entire div.
I used only pure Javascript, since your code was the same way.
I'm having a problem with a script that generates a live preview of the image file that I select. The problem is that there is a spike in memory when I select a file using the file input, so my on('change') method fires much too late for a useful user response. Now if I hit Ctrl+F5, sometimes the browser becomes much more responsive and generates the preview very quickly. The lag isn't in the inlining of image data, but the time between when the user selects "open" on the file dialog box and when the onChange event fires. I don't know how to track what's going on in between those two events.
I have hidden the HTML file input tag via CSS positioning and triggered the click event when I click on a separate span element. The input tag has the on('change') function registered. On change, I notify the user that the image preview is being generated. When the generation is complete, I notify "Preview complete". As I stated before, due to the fact that the onchange event is lagged due to memory spikes, I never end up seeing the intermediary "please wait..." text. This happens both in Firefox and Chrome.
javascript
var imageSelectClass = '';
var imageSelectDefaultBGSize = 'auto';
var imageSelectWorkingBGSize = '100%';
var imageSelectDefaultUrl = '';
var imageSelectNoPreviewUrl = '';
function resetImageSelection(resetImage, toOriginalImage) {
$('.image-select-text').text("");
$('.image-select-text').css("opacity", 1);
$('.' + imageSelectClass).css('backgroundSize', imageSelectDefaultBGSize);
if (resetImage) {
if (toOriginalImage) $('.' + imageSelectClass).css('backgroundSize', imageSelectWorkingBGSize);
if (imageSelectDefaultUrl != imageSelectNoPreviewUrl) {
$('.' + imageSelectClass).css('backgroundImage', "url('" + (toOriginalImage ? imageSelectDefaultUrl : imageSelectNoPreviewUrl) + "')");
}
}
}
function handleImageSelection(evt) {
// Clear the photo box
resetImageSelection(true, true);
var files = evt.target.files; // FileList object
// Loop through the FileList and render image files as thumbnails.
for (var i = 0, f; f = files[i]; i++) {
// Only process image files.
if (!f.type.match('image.*')) {
evt.preventDefault();
resetImageSelection(true, true);
$('#' + imageSelectClass).replaceWith($('#' + imageSelectClass).clone());
makeIntoImageSelection(imageSelectClass, imageSelectDefaultUrl, imageSelectNoPreviewUrl, imageSelectDefaultBGSize, imageSelectWorkingBGSize);
newTextMessage("Not an image file!", 2000, 400);
continue;
}
var isValidPreview = f.type.match('image\/(jp(e?)g|png|gif|bmp)');
//var reader = new FileReader();
var theType = /\/(.*)/.exec(f.type)[1].toUpperCase();
// Limit preview to 20MB file sizes
var limit = 20971520;
if (f.size < limit) {
if (isValidPreview) {
resetImageSelection(false, false);
var URL = window.URL || window.webkitURL;
if (URL.createObjectURL) {
newTextMessage("Preview generated.", 3000, 400);
$('.' + imageSelectClass).css('backgroundSize', imageSelectWorkingBGSize);
$('.' + imageSelectClass).css('backgroundImage', "url('" + URL.createObjectURL(f) + "')");
} else {
resetImageSelection(true, false);
newTextMessage("Sorry, but your browser doesn't support image previews.", 0, 0);
}
} else {
resetImageSelection(true, false);
newTextMessage(theType + " images can't be previewed 'on-the-fly'. However it will be converted when you save.", 0, 0);
}
} else {
resetImageSelection(true, false);
newTextMessage("On-the-fly previews only available for files <= " + (limit/1024/1024) + "MB", 0, 0);
}
}
}
function makeIntoImageSelection(id, defaultUrl, noPreviewUrl, defaultBGSize, workingBGSize) {
imageSelectClass = id;
originalCanvasWidth = $('.' + id).width();
originalCanvasHeight = $('.' + id).height();
imageSelectDefaultBGSize = defaultBGSize;
imageSelectWorkingBGSize = workingBGSize;
imageSelectDefaultUrl = defaultUrl;
imageSelectNoPreviewUrl = noPreviewUrl;
// When span is clicked, trigger the file input
$('span.' + id).on('click', function(evt) {
evt.preventDefault();
$('#' + id).click();
newTextMessage("Select an image.", 3000, 400);
});
$('#' + id).on('change', function (evt) {
newTextMessage("Generating preview...", 2000, 400);
handleImageSelection(evt);
});
$('.image-select-text').css('maxWidth', $('.image-select.' + id + ' span').css('width'));
}
function newTextMessage(msg, display_time, fadeDelay) {
$('.image-select-text').text(msg);
$('.image-select-text').css("opacity", 1);
if (display_time > 0) {
$('.image-select-text').delay(display_time).fadeTo(fadeDelay, 0, function() {
$('.image-select-text').text("");
$('.image-select-text').css("opacity", 1);
});
}
}
HTML
<form accept-charset="UTF-8" action="/albums/4/photographs" class="new_photograph" enctype="multipart/form-data" id="new_photograph" method="post">
<div style="margin:0;padding:0;display:inline"></div>
<input class="image-select" id="photograph_photo" name="photograph[photo]" type="file">
<table>
<tbody>
<tr>
<td>
<span class="image-select photograph_photo" style="background-size: 100%;"></span><br>
<span class="image-select-text" style="opacity: 1;"></span>
</td>
</tr>
<tr>
<td><label for="photograph_title">Title</label><br><input id="photograph_title" name="photograph[title]" size="50" type="text" data-cip-id="photograph_title"></td>
</tr>
<tr>
<td><label for="photograph_description">Description</label><br><textarea id="photograph_description" name="photograph[description]"></textarea></td>
</tr>
</tbody>
</table>
<br>
<div class="actions">
<input name="commit" type="submit" value="Create Photograph">
</div>
</form>
Inline Javascript at end of document
makeIntoImageSelection('photograph_photo', '[url of original image file if any]', '[url of global default image file]', '100%', '100%');
I really can't say what was causing such lag, but I'm going to chalk it up to "weird circumstances. A computer restart had essentially 'fixed' the problem.