Example: Simple Multiple Files Uploader with Progress Tracking

In this example, the Uploader is used to send multiple images or videos to the server and monitor their upload progress with individual counters.

Please note: This example will not work when run from a local filesystem because of security restrictions in the transport protocols used. If you’d like to run this example locally, set up a local web server and launch it from there.

Also note: The uploader is not supported on iOS devices (iPhone and iPad), because they lack file upload capability. This example provides a graceful degradation message for all such systems.

Also note: The backend script used in these examples does not store any information it receives. Nevertheless, do not submit any sensitive or private data and keep your tests to a few small files to avoid overloading the system.

File nameFile sizePercent uploaded
No files have been selected.

Setting up Uploader UI

In this example, the UI for the Uploader consists of two buttons, a label field for displaying the uploader type and the overall upload progress, as well as a table for displaying information about the upload process per file. We first create the markup for the UI:

<div id="uploaderContainer">
   <div id="selectFilesButtonContainer">
   </div> 
   <div id="uploadFilesButtonContainer">
     <button type="button" id="uploadFilesButton" 
             class="yui3-button" style="width:250px; height:35px;">Upload Files</button>
   </div> 
   <div id="overallProgress">
</div>

<div id="filelist">
  <table id="filenames">
    <thead>
       <tr><th>File name</th><th>File size</th><th>Percent uploaded</th></tr>
       <tr id="nofiles">
        <td colspan="3">
            No files have been selected.
        </td>
       </tr>
    </thead>
    <tbody>
    </tbody>
  </table> 
</div>

Next, we create, configure and render an instance of the Uploader. Note that we initially check that the Y.Uploader.TYPE property is not set to 'none' and that we are not trying to run the code on an iOS device (where file uploads are not allowed because of a closed file system). Also note that we are setting a fixed width and height on the uploader, which is necessary in order for the Flash overlay to render correctly in browsers where Flash is used:

if (Y.Uploader.TYPE != "none" && !Y.UA.ios) { 
    var uploader = new Y.Uploader({width: "250px", 
                                   height: "35px", 
                                   multipleFiles: true,
                                   swfURL: "../../build/uploader/assets/flashuploader.swf?t=" + Math.random(),
                                   uploadURL: "http://www.yswfblog.com/upload/simpleupload.php",
                                   simLimit: 2,
                                   withCredentials: false
                                  });  

    var uploadDone = false;

    uploader.render("#selectFilesButtonContainer");

    ...

Adding Uploader Event Handlers

We can now add handlers for various uploader events. The first handler is for the fileselect event. In it, we retrieve the list of files selected by the user and populate the table with their names, sizes and a field for reporting the percentage uploaded for each file. The id of each row in the table is prefixed with the unique file id it is associated with, for easy reference later:

uploader.after("fileselect", function (event) {
   var fileList = event.fileList;
   var fileTable = Y.one("#filenames tbody");
   if (fileList.length > 0 && Y.one("#nofiles")) {
     Y.one("#nofiles").remove();

   if (uploadDone) {
     uploadDone = false;
     fileTable.setHTML("");
   }
   
   Y.each(fileList, function (fileInstance) {
       fileTable.append("<tr id='" + fileInstance.get("id") + "_row" + "'>" + 
                             "<td class='filename'>" + fileInstance.get("name") + "</td>" + 
                             "<td class='filesize'>" + fileInstance.get("size") + "</td>" + 
                             "<td class='percentdone'>Hasn't started yet</td>"); 
   });
});

For the uploadprogress event, we update the individual file row (using the unique file id prefix to reference each row) with the percentLoaded property from the event payload.

uploader.on("uploadprogress", function (event) {
     var fileRow = Y.one("#" + event.file.get("id") + "_row");
         fileRow.one(".percentdone").set("text", event.percentLoaded + "%");
});

When the upload starts, we disable the uploader and the Upload Files button until the upload process is complete:

uploader.on("uploadstart", function (event) {
     uploader.set("enabled", false);
     Y.one("#uploadFilesButton").addClass("yui3-button-disabled");
     Y.one("#uploadFilesButton").detach("click");
});

When each individual file upload completes, we update the table row corresponding with the file with the appropriate message:

uploader.on("uploadcomplete", function (event) {
     var fileRow = Y.one("#" + event.file.get("id") + "_row");
         fileRow.one(".percentdone").set("text", "Finished!");
});

On totaluploadprogress events, we report the overall upload progress in the top-right message container:

uploader.on("totaluploadprogress", function (event) {
         Y.one("#overallProgress").setHTML("Total uploaded: <strong>" + event.percentLoaded + "%" + "</strong>");
});

We can listen for the alluploadscomplete event to find out when all uploads have completed, re-enable the uploader and report that information accordingly:

uploader.on("alluploadscomplete", function (event) {
              uploader.set("enabled", true);
              uploader.set("fileList", []);
              Y.one("#uploadFilesButton").removeClass("yui3-button-disabled");
              Y.one("#uploadFilesButton").on("click", function () {
                 if (!uploadDone && uploader.get("fileList").length > 0) {
                    console.log(uploader.get("fileList").length);
                    uploader.uploadAll();
              });
              Y.one("#overallProgress").set("text", "Uploads complete!");
              uploadDone = true;
});

Finally, we add the click event listener to the "Upload Files" button to start the file upload process:

Y.one("#uploadFilesButton").on("click", function () {
  if (!uploadDone && uploader.get("fileList").length > 0) {
     console.log(uploader.get("fileList").length);
     uploader.uploadAll();
  }
});

Full Source Code For this Example

<style>
#filelist {
    margin-top: 15px;
}

#uploadFilesButtonContainer, #selectFilesButtonContainer, #overallProgress {
    display: inline-block;
}

#overallProgress {
    float: right;
}
</style>

<div id="uploaderContainer"> 
    <div id="selectFilesButtonContainer">
    </div> 
    <div id="uploadFilesButtonContainer">
      <button type="button" id="uploadFilesButton" 
              class="yui3-button" style="width:250px; height:35px;">Upload Files</button>
    </div> 
    <div id="overallProgress">
    </div>
</div> 

<div id="filelist">
  <table id="filenames">
    <thead>
       <tr><th>File name</th><th>File size</th><th>Percent uploaded</th></tr>
       <tr id="nofiles">
        <td colspan="3">
            No files have been selected.
        </td>
       </tr>
    </thead>
    <tbody>
    </tbody>
  </table>  
</div>

<script>

YUI({filter:"raw"}).use("uploader", function(Y) {
Y.one("#overallProgress").set("text", "Uploader type: " + Y.Uploader.TYPE);
   if (Y.Uploader.TYPE != "none" && !Y.UA.ios) { 
       var uploader = new Y.Uploader({width: "250px", 
                                      height: "35px", 
                                      multipleFiles: true,
                                      swfURL: "../../build/uploader/assets/flashuploader.swf?t=" + Math.random(),
                                      uploadURL: "http://www.yswfblog.com/upload/simpleupload.php",
                                      simLimit: 2,
                                      withCredentials: false
                                     });    
       var uploadDone = false;

       uploader.render("#selectFilesButtonContainer");

       uploader.after("fileselect", function (event) {

          var fileList = event.fileList;
          var fileTable = Y.one("#filenames tbody");
          if (fileList.length > 0 && Y.one("#nofiles")) {
            Y.one("#nofiles").remove();
          }

          if (uploadDone) {
            uploadDone = false;
            fileTable.setHTML("");
          }
          
          Y.each(fileList, function (fileInstance) {
              fileTable.append("<tr id='" + fileInstance.get("id") + "_row" + "'>" + 
                                    "<td class='filename'>" + fileInstance.get("name") + "</td>" + 
                                    "<td class='filesize'>" + fileInstance.get("size") + "</td>" + 
                                    "<td class='percentdone'>Hasn't started yet</td>"); 
                             });
       });

       uploader.on("uploadprogress", function (event) {
            var fileRow = Y.one("#" + event.file.get("id") + "_row");
                fileRow.one(".percentdone").set("text", event.percentLoaded + "%");
       });

       uploader.on("uploadstart", function (event) {
            uploader.set("enabled", false);
            Y.one("#uploadFilesButton").addClass("yui3-button-disabled");
            Y.one("#uploadFilesButton").detach("click");
       });

       uploader.on("uploadcomplete", function (event) {
            var fileRow = Y.one("#" + event.file.get("id") + "_row");
                fileRow.one(".percentdone").set("text", "Finished!");
       });

       uploader.on("totaluploadprogress", function (event) {
                Y.one("#overallProgress").setHTML("Total uploaded: <strong>" + event.percentLoaded + "%" + "</strong>");
       });

       uploader.on("alluploadscomplete", function (event) {
                     uploader.set("enabled", true);
                     uploader.set("fileList", []);
                     Y.one("#uploadFilesButton").removeClass("yui3-button-disabled");
                     Y.one("#uploadFilesButton").on("click", function () {
                          if (!uploadDone && uploader.get("fileList").length > 0) {
                             uploader.uploadAll();
                          }
                     });
                     Y.one("#overallProgress").set("text", "Uploads complete!");
                     uploadDone = true;
       });

       Y.one("#uploadFilesButton").on("click", function () {
         if (!uploadDone && uploader.get("fileList").length > 0) {
            uploader.uploadAll();
         }
       });     
   } 
   else {
       Y.one("#uploaderContainer").set("text", "We are sorry, but to use the uploader, you either need a browser that support HTML5 or have the Flash player installed on your computer.");
   }


});

</script>