Topic: 02. Bring Plupload to life

Previous: Quick Start

In order to present user with friendly visuals, simple structure that we’ve used in our Quick Start Intro is not enough. Contemporary file uploader, in addition to that, should display the list of files to upload, upload progress and result of the whole procedure, whether it was successful or not.

In this tutorial we will make use of two useful Plupload events to achieve these goals: FilesAdded and UploadProgress. We will also take a look at the Error event, which is crucial to gracefully survive the error, that might happen either before upload, during the upload, or after it.

There are two different ways to bind event listeners in Plupload, both having their own purpose. But for the purpose of this tutorial we will consider only first one, which will be used in 99% of all possible usage cases.

Let’s start by adding visual feedback for the files added to the queue. We will use the same file structure, we’ve used in Quick Start guide and simply add necessary code to the index.html. Here it is:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Introduction to Plupload</title>

<script type="text/javascript" src="js/plupload.full.js"></script>
</head>
<body>

<div id="uploader">
    <p>Upload Files:</p>

    <div id="filelist"> </div>
    <br />
    
    <a id="pickfiles" href="javascript:;">Add Files</a>
    <a id="uploadfiles" href="javascript:;">Start Upload</a> 

</div>

<script type="text/javascript">
//<![CDATA[

    var uploader = new plupload.Uploader({
        runtimes: 'flash',
        flash_swf_url: 'js/plupload.flash.swf',
        browse_button: 'pickfiles',
        url: 'upload.php'
    });
    
    uploader.init();

    uploader.bind(‘FilesAdded’, function(up, files) {
    // handler code...
    });
    
    document.getElementById('uploadfiles').onclick = function() {
        uploader.start();
    };

//]]>
</script>
</body>
</html>

We’ve added <div id="filelist"> </div> container, which will serve us as the visual list of files in the queue.

Notice also that we call uploader.bind() after we initialize Plupload instance with uploader.init(). It is also possible to bind an event handler before the call to uploader.init(), but such operation might result in completely different behavior, despite the fact that it might look to some as the same. The rule of the thumb here would be to always bind event handlers after the call to uploader.init(), unless you really know what you are doing and you are doing it on purpose. Otherwise expect unexpected results.

FilesAdded receives two arguments: reference to uploader object (actually all Plupload event handlers receive the reference to uploader instance as a first argument) and array of file objects that were selected in file dialog (by default, you can select multiple files, if the current Plupload runtime has support for this of course).

Let’s populate our FilesAdded handler with some code: essential thing here would be to create DOM elements, representing every file added to the queue:

uploader.bind(‘FilesAdded’, function(up, files) {
    // loop through the files array
    for (var i in files) {
        document.getElementById('filelist').innerHTML += '<div id="' + files[i].id + '">' + files[i].name + ' (' + plupload.formatSize(files[i].size) + ') <b></b></div>';
    }
});

We simply loop through the files array and for each file object append a div to #filelist element, containing file name and having unique id of the file as id attribute. There is also an empty <b> </b> element inside the file div, which we will use to display upload percentage.

Now that we got a logic for file selection, let’s bring our Plupload structure to life with the feedback from upload progress:

uploader.bind('UploadProgress', function(up, file) {
    document.getElementById(file.id).getElementsByTagName('b')[0].innerHTML = '<span>' + file.percent + "%</span>";
});

As you see UploadProgress receives two arguments - reference to uploader object, and reference to the file object being uploaded. What we do is simply find the empty <b> </b> element within the corresponding file div container and update it’s innerHTML with current upload percentage. Just that simple.

The only thing left now, would be proper error handling:

uploader.bind('Error', function(up, args) {
    alert(args.code + ‘: ‘ + args.message);
});

We simply alert the error - for our example it would be enough. The main point is to let users know, that something went wrong.

Here is how index.html should look like after the change:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Introduction to Plupload</title>

<script type="text/javascript" src="js/plupload.full.js"></script>
</head>
<body>

<div id="uploader">
    <p>Upload Files:</p>

    <div id="filelist"> </div>
    <br />
    
    <a id="pickfiles" href="javascript:;">Add Files</a>
    <a id="uploadfiles" href="javascript:;">Start Upload</a> 

</div>

<script type="text/javascript">
//<![CDATA[

    var uploader = new plupload.Uploader({
        runtimes: 'flash',
        flash_swf_url: 'js/plupload.flash.swf',
        browse_button: 'pickfiles',
        url: 'upload.php'
    });
    
    uploader.init();

   uploader.bind('FilesAdded', function(up, files) {
        // loop through the files array
        for (var i in files) {
            document.getElementById('filelist').innerHTML += '<div id="' + files[i].id + '">' + files[i].name + ' (' + plupload.formatSize(files[i].size) + ') <b></b></div>';
        }
    });
    
    uploader.bind('UploadProgress', function(up, file) {
        document.getElementById(file.id).getElementsByTagName('b')[0].innerHTML = '<span>' + file.percent + "%</span>";
    });
    
    uploader.bind('Error', function(up, args) {
        alert(args.code + ': ' + args.message);
    });
    
    document.getElementById('uploadfiles').onclick = function() {
        uploader.start();
    };

//]]>
</script>
</body>
</html>
If you want to see your issue fixed, do not report it here, do it on - GitHub.