Reputation: 157
I am trying to upload multiple images with File API. I want to show picture thumbnails and their names as title tag. The problem is I am not getting correct picture name as title tag. All pictures are showing same name. Here is my Original code...
jQuery, CSS and HTML
var output = document.getElementById("result");
$(document).ready(function ()
{
//Check File API support
if (window.File && window.FileList && window.FileReader)
{
$('#files').on("change", function (event)
{
var files = event.target.files; //FileList object
var iCount = files.length;
for (var i = 0, f; i < iCount; i++)
{
var file = files[i];
//Only pics
if (file.type.match('image.*'))
{
var picReader = new FileReader();
picReader.addEventListener("load", function (event)
{
var picFile = event.target;
var div = document.createElement("div");
div.innerHTML = "<img class='thumbnail' src='" + picFile.result + "'" +
"title='" + file['name'] + "'/>";
output.insertBefore(div, null);
});
//Read the image
$('#clear, #result').show();
picReader.readAsDataURL(file);
}
else
{
alert("You can only upload image file.");
$(this).val("");
}
}
});
}
else
{
console.log("Your browser does not support File API");
}
$("#upload").on('submit',(function()
{
var data = new FormData(this);
var iUploaded = 0;
setTimeout(function()
{
var iCount = document.getElementById('files').files.length;
for (var i = 0; i < iCount ; i++)
{
data.append("Index", i);
$.ajax(
{
url: "upload.php",
type: "POST",
data: data,
contentType: false,
cache: false,
processData:false,
async: false,
success: function(response)
{
var sRes = response.split("|-|");
if(sRes['0'] == 'success')
{
iUploaded = iUploaded + 1;
$("#message").html(iUploaded + " of " + sRes['1'] + " Pictures Uploaded")
}
}
});
}
}, 500);
}));
$("#files").change(function()
{
$("#submit").trigger("click");
});
$('#clear').on("click", function ()
{
$('.thumbnail').parent().remove();
$('#result').hide();
$('#files').val("");
$(this).hide();
});
});
body{
font-family: 'Segoe UI';
font-size: 12pt;
}
header h1{
font-size:12pt;
color: #fff;
background-color: #1BA1E2;
padding: 20px;
}
article
{
width: 80%;
margin:auto;
margin-top:10px;
}
.thumbnail{
height: 100px;
margin: 10px;
float: left;
}
#clear{
display:none;
}
#result {
border: 4px dotted #cccccc;
display: none;
float: left;
margin:0 auto;
}
#result > div {
float: left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<article>
<form id="upload" onsubmit="return false">
<label for="files">Select multiple files: </label><br /><br />
<input id="files" name="files[]" type="file" multiple/><br /><br />
<input type="Submit" value="submit" id="submit"></input>
<button type="button" id="clear">Clear</button><br /><br />
</form>
<div id="message"></div>
<output id="result" />
</article>
I tried to figure it out and come to know that the value of var i
changes automatically inside the
addEventListener("load", function (event){
// value of “var i” is not the same here as the value coming from outside this function.
});
I have no idea why value is changing inside the “load” function.
I Googled to see how others are doing same and ended up with this working example on SitePoint http://www.sitepoint.com/html5-file-drag-and-drop/ In this example I see these 2 major differences which I do not understand (my little knowledge in programming).
1. Syntax of for loop he is using in example
for (var i = 0, f; f = files[i]; i++) {
See he is assigning value to var f
instead of applying stop condition.
Now my question is how the loop is working without stop condition is specified?
2. Separate function for reading files
He has made a separate function ParseFile();
to read files.
When I tried to read files without a separate function for file reading it is not working (as shown in my original code). But when I put that code in a separate function showThumbnail()
for reading files and call that function inside loop it is working as it should be (as showing in below snippet). Why is this so?
Anyone here explain these two things to me. Thanks in advance.
I followed the example and rearranged my code which is working as it should be. (Code is in below snippet.)
var output = document.getElementById("result");
$(document).ready(function ()
{
//Check File API support
if (window.File && window.FileList && window.FileReader)
{
$('#files').on("change", function (event)
{
var files = event.target.files; //FileList object
var iCount = files.length;
for (var i = 0, f; f = files[i]; i++)
{
showThumbnail(f);
}
});
}
else
{
console.log("Your browser does not support File API");
}
$("#upload").on('submit',(function()
{
var data = new FormData(this);
var iUploaded = 0;
setTimeout(function()
{
var iCount = document.getElementById('files').files.length;
for (var i = 0; i < iCount ; i++)
{
data.append("Index", i);
$.ajax(
{
url: "upload.php",
type: "POST",
data: data,
contentType: false,
cache: false,
processData:false,
async: false,
success: function(response)
{
var sRes = response.split("|-|");
if(sRes['0'] == 'success')
{
iUploaded = iUploaded + 1;
$("#message").html(iUploaded + " of " + sRes['1'] + " Pictures Uploaded")
}
}
});
}
}, 500);
}));
$("#files").change(function()
{
$("#submit").trigger("click");
});
$('#clear').on("click", function ()
{
$('.thumbnail').parent().remove();
$('#result').hide();
$('#files').val("");
$(this).hide();
});
});
function showThumbnail(file)
{
//Only pics
if (file.type.match('image.*'))
{
var picReader = new FileReader();
picReader.addEventListener("load", function (event)
{
var picFile = event.target;
var div = document.createElement("div");
div.innerHTML = "<img class='thumbnail' src='" + picFile.result + "'" +
"title='" + file['name'] + "'/>";
output.insertBefore(div, null);
});
//Read the image
$('#clear, #result').show();
picReader.readAsDataURL(file);
}
else
{
alert("You can only upload image file.");
$(this).val("");
}
}
body{
font-family: 'Segoe UI';
font-size: 12pt;
}
header h1{
font-size:12pt;
color: #fff;
background-color: #1BA1E2;
padding: 20px;
}
article
{
width: 80%;
margin:auto;
margin-top:10px;
}
.thumbnail{
height: 100px;
margin: 10px;
float: left;
}
#clear{
display:none;
}
#result {
border: 4px dotted #cccccc;
display: none;
float: left;
margin:0 auto;
}
#result > div {
float: left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<article>
<form id="upload" onsubmit="return false">
<label for="files">Select multiple files: </label><br /><br />
<input id="files" name="files[]" type="file" multiple/><br /><br />
<input type="Submit" value="submit" id="submit"></input>
<button type="button" id="clear">Clear</button><br /><br />
</form>
<div id="message"></div>
<output id="result" />
</article>
Upvotes: 1
Views: 1863
Reputation: 1608
Answer to question 1:
The for loop increments i
with 1 on every iteration. When i
is not an index of files
the returned value will be undefined, which breaks the loop.
Answer to question 2:
I created a fiddle which shows how to put the code of showThumbnail
in the for loop. It aslo explains the question.
The reason is behind the addEventListener
function, which will run asynchronously with the for loop after load
is triggered and has different scope. The function outside the loop is however permanent and the listener can use variables declared in that scope (the argument file
).
What you can do however is to bind the listener function to the file object. The scope (this
) of the function will be the file. See the fiddle for this to work.
Upvotes: 0
Reputation: 136716
Haven't seen the edits to question before posting + misread it
So for your questions :
1 This for loop is waiting for file[i] to be undefined. :
for( var i=0, f; f=files[i]; i++)
.
If files[x]
is undefined, then the loop stops (even if files[x+1] is defined)
2 It is because in your first snippet, your file
variable is in the global scope and gets replaced during the iteration. In the second, however, it is linked to the showThumbnail
function scope, and then passed in the EventListener.
To avoid calling an external function, you will need to call a file
binded function :
From mdn : reader.onload = (function(aImg) { return function(e) { aImg.src = e.target.result; }; })(img);
So for you,
picReader.addEventListener("load", (function(aImg) { return function (event)
{
var picFile = event.target;
console.log(picFile);
var div = document.createElement("div");
div.innerHTML = "<img class='thumbnail' src='" + picFile.result + "'" +
"title='" + aImg['name'] + "'/>";
output.insertBefore(div, null);
}; })(file));
Example below :
var output = document.getElementById("result");
$(document).ready(function ()
{
//Check File API support
if (window.File && window.FileList && window.FileReader)
{
$('#files').on("change", function (event)
{
var files = event.target.files; //FileList object
var iCount = files.length;
for (var i = 0, f; i < iCount; i++)
{
var file = files[i];
//Only pics
if (file.type.match('image.*'))
{
var picReader = new FileReader();
picReader.addEventListener("load", (function(aImg) { return function (event)
{
var picFile = event.target;
console.log(picFile);
var div = document.createElement("div");
div.innerHTML = "<img class='thumbnail' src='" + picFile.result + "'" +
"title='" + aImg['name'] + "'/>";
output.insertBefore(div, null);
}; })(file));
//Read the image
$('#clear, #result').show();
picReader.readAsDataURL(file);
}
else
{
alert("You can only upload image file.");
$(this).val("");
}
}
});
}
else
{
console.log("Your browser does not support File API");
}
$("#upload").on('submit',(function()
{
var data = new FormData(this);
var iUploaded = 0;
setTimeout(function()
{
var iCount = document.getElementById('files').files.length;
for (var i = 0; i < iCount ; i++)
{
data.append("Index", i);
$.ajax(
{
url: "upload.php",
type: "POST",
data: data,
contentType: false,
cache: false,
processData:false,
async: false,
success: function(response)
{
var sRes = response.split("|-|");
if(sRes['0'] == 'success')
{
iUploaded = iUploaded + 1;
$("#message").html(iUploaded + " of " + sRes['1'] + " Pictures Uploaded")
}
}
});
}
}, 500);
}));
$("#files").change(function()
{
$("#submit").trigger("click");
});
$('#clear').on("click", function ()
{
$('.thumbnail').parent().remove();
$('#result').hide();
$('#files').val("");
$(this).hide();
});
});
body{
font-family: 'Segoe UI';
font-size: 12pt;
}
header h1{
font-size:12pt;
color: #fff;
background-color: #1BA1E2;
padding: 20px;
}
article
{
width: 80%;
margin:auto;
margin-top:10px;
}
.thumbnail{
height: 100px;
margin: 10px;
float: left;
}
#clear{
display:none;
}
#result {
border: 4px dotted #cccccc;
display: none;
float: left;
margin:0 auto;
}
#result > div {
float: left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<article>
<form id="upload" onsubmit="return false">
<label for="files">Select multiple files: </label><br /><br />
<input id="files" name="files[]" type="file" multiple/><br /><br />
<input type="Submit" value="submit" id="submit"></input>
<button type="button" id="clear">Clear</button><br /><br />
</form>
<div id="message"></div>
<output id="result" />
</article>
Upvotes: 1