I tried to figure this out for over a month now. I cannot get the image to be removed from the array once the image was clicked on \'x\' on the previewer.
http://jsf
From what I understand in your question, you're trying to remove a file from a multifile input form. Unfortunately this is not possible due to security restrictions in all browsers. The multifile input returns a read-only FileList
, which contains a collection of File
objects. Therefore you can't simply remove an element from the list. (Checkout this question.)
There is a workaround, though, which requires AJAX for handling the form. You can process the FileList
and store the files in an array. Then attach an on('submit')
function which will intercept the submit action. Instead of a submit event, an $.ajax()
request, sending the serialized form will be made.
Example:
<!-- upload.html -->
<!DOCTYPE html>
<html>
<head lang="en">
<title>Upload</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="//code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
<style type="text/css">
ul{
width: 650px;
}
ul li {
list-style: none;
width: 165px;
float:left;
position: relative;
margin: 0px 0px 0px 20px;
}
.thumb {
width: 150px;
}
.remove {
position: absolute;
top: 0px;
right: 0px;
color: red;
cursor: pointer;
}
/* Prettify json output.. not needed in your code */
pre {outline: 1px solid #ccc; padding: 5px; margin: 5px; }
.string { color: green; }
.number { color: darkorange; }
.boolean { color: blue; }
.null { color: magenta; }
.key { color: red; }
</style>
<script type="text/javascript">
$(document).ready(function() {
// You don't need this - it's used only for the demo.
function jsonPrettify(json) {
if (typeof json != 'string') {
json = JSON.stringify(json, undefined, 2);
}
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
var cls = 'number';
if (/^"/.test(match)) {
if (/:$/.test(match)) {
cls = 'key';
} else {
cls = 'string';
}
} else if (/true|false/.test(match)) {
cls = 'boolean';
} else if (/null/.test(match)) {
cls = 'null';
}
return '<span class="' + cls + '">' + match + '</span>';
});
}
// You don't need this - it's used only for the demo.
// The code
var filesArray = [];
/**
* This function processes all selected files
*
* @param e eventObject
*/
function previewFiles( e ) {
// FileList object
var files = e.target.files;
var preview = $('#imagePreviews');
// 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.*')) {
continue;
}
var reader = new FileReader();
// Closure to capture the file information.
reader.onload = (function(theFile) {
return function(e) {
// Render thumbnail.
var li = $('<li><img class="thumb" src="'+ e.target.result +'" title="'+ escape(theFile.name) +'"/><div class="remove">X</div></li>');
preview.append(li);
// Append image to array
filesArray.push(theFile);
};
})(f,preview);
// Read the image file as a data URL.
reader.readAsDataURL(f);
}
}
// Attach on change to the file input
$('#fileInput').on('change', previewFiles);
/**
* Remove the file from the array list.
*
* @param index integer
*/
function removeFile( index ){
filesArray.splice(index, 1);
}
// Attach on click listener which will handle the removing of images.
$(document).on('click', '#imagePreviews .remove',function(e){
var image = $(this).closest('li');
console.log(image.index());
// Remove the image from the array by getting it's index.
// NOTE: The order of the filesArray will be the same as you see it displayed, therefore
// you simply need to get the file's index to "know" which item from the array to delete.
console.log('Files:' ,filesArray);
removeFile(image.index());
console.log('Files:' ,filesArray);
// Fadeout the image and remove it from the UI.
image.fadeOut(function(){
$(this).remove();
});
});
/**
* This function processes the submission of the form.
*
* @param e
*/
function submitForm(e){
// Stop the form from actually submitting.
e.preventDefault();
// Create a new FormData based on our current form.
// Makes live easier as we can attach a list of File objects.
var formData = new FormData($('#myForm')[0]);
for(var i= 0, file; file = filesArray[i]; i++){
formData.append('files[]', file);
}
// Send the ajax request.
$.ajax({
url: 'upload.php',
type: 'POST',
data: formData,
processData: false,
contentType: false,
success: function(response) {
$('#response').html(jsonPrettify(response));
}
});
}
// Attach on submit to the form submission.
$('#myForm').on('submit', submitForm);
});
</script>
</head>
<body>
<div style="width: 650px; border: 1px #D8D8D8;">
<form id="myForm" action="upload.php" method="post" enctype="multipart/form-data">
<label>Name</label>
<input type="text" name="firstName" value="FirstName"/>
<input type="text" name="lastName" value="LastName"/>
<!-- Don't set a name of this input so that we won't need to remove it before serialization. -->
<input id="fileInput" type="file" value="Upload button" multiple/>
<div style="width: 600px; border: 1px solid #D8D8D8;">
<ul style="list-style: none;" id="imagePreviews">
</ul>
<div style="clear: both;"> </div>
</div>
<br>
<input type="submit"/>
</form>
<br>
Upload.php response<br>
<pre id="response" style="width: 650px;"></pre>
</div>
</body>
</html>
// upload.php
<?php
header('Content-Type: application/json');
echo json_encode(array('success' => true, '$_FILES' => $_FILES, '$_POST' => $_POST));
?>
Hope this helps.
jsBin demo
var $fileUpload = $("#files"),
$list = $('#list'),
thumbsArray = [],
maxUpload = 5;
// READ FILE + CREATE IMAGE
function read( f ) {
return function( e ) {
var base64 = e.target.result;
var $img = $('<img/>', {
src: base64,
title: encodeURIComponent(f.name), //( escape() is deprecated! )
"class": "thumb"
});
var $thumbParent = $("<span/>",{html:$img, "class":"thumbParent"}).append('<span class="remove_thumb"/>');
thumbsArray.push(base64); // Push base64 image into array or whatever.
$list.append( $thumbParent );
};
}
// HANDLE FILE/S UPLOAD
function handleFileSelect( e ) {
e.preventDefault(); // Needed?
var files = e.target.files;
var len = files.length;
if(len>maxUpload || thumbsArray.length >= maxUpload){
return alert("Sorry you can upload only 5 images");
}
for (var i=0; i<len; i++) {
var f = files[i];
if (!f.type.match('image.*')) continue; // Only images allowed
var reader = new FileReader();
reader.onload = read(f); // Call read() function
reader.readAsDataURL(f);
}
}
$fileUpload.change(function( e ) {
handleFileSelect(e);
});
$list.on('click', '.remove_thumb', function () {
var $removeBtns = $('.remove_thumb'); // Get all of them in collection
var idx = $removeBtns.index(this); // Exact Index-from-collection
$(this).closest('span.thumbParent').remove(); // Remove tumbnail parent
thumbsArray.splice(idx, 1); // Remove from array
});
To explain the pain above:
the thumbnails created by the above code look like:
<span class="thumbParent">
<img class="thumb" src="base64string....">
<span class="remove_thumb"></span>
</span>
now, clicking the remove thumbnail Button we need to get a collection of those buttons in order to create an index variable (that will later .splice() our images array) by doing:
$removeBtns.index(this)
.
I know I edited a bit the classNames, feel free to undo if you want.