简体   繁体   中英

HTML5 File API Upload Multiple Images with Ajax

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> 

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> 

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM