Friday, 30 December 2011

NeatUpload jQuery plugin – Examples – Part 3

In my last post I covered three scenarios where we changed the cancel the link element and start upload immediately. Well, let's continue tweaking, in this case the turn is for the user experience, I’ll show how to display a fancy progress bar while the upload operation is in progress, validate elements before send the file and even send extra data attached to the uploaded file. Let’s start.

Scenario 5 – Showing a fancy progress bar.

In all previous examples I have shown a simple number followed by a “%” symbol to indicate the progress, but I real life the user experience should be more than that, so all we are accustomed to is to see a progress bar increasing its size horizontally until the maximum width is reached, or tell me if I am crazy!? At least Graphical User Interfaces have used this pattern for years and it works. So if we intercept the moment when the file is added to the queue, it’s possible take the control and to construct everything necessary for display the progress. Let’s check the code:
<link href="@Url.Content("~/Content/progress.css")" rel="stylesheet" type="text/css" />

fnShowStatus: function (plugin, index, data) {
    $('table[id=tablequeue] > tbody > tr[data-neatupload-rowprog=' + index + '] div.progress-bar').width(data.PercentComplete + "%");
},
fnAddFile: function (plugin, filename, form, index) {
    var cancel = plugin.options.createCancelLink(plugin, index);
    var row1 = $("<tr data-neatupload-rowname='" + index + "' class='uploadItem-uploading'></tr>");
    var row2 = $("<tr data-neatupload-rowprog='" + index + "' class='uploadItem-uploading'></tr>");
    $('table[id=tablequeue] > tbody')
        .append(row1).append(row2);
    row1.append($("<td style='width: 80%'></td>")
        .append("<div class='uploading-video-name'>" + name + "</div>")
        .append("<div class='uploading-video-file-name'>" + filename + "</div>"))
    .append($("<td></td>"));
    row2.append($("<td></td>")
        .append($("<div class='barcontainer'></div>")
        .append("<div style='width: 0%' class='progress-bar'>")))
    .append($("<td class='cancel'></td>").append(cancel));
},
fnRemoveFile: function (plugin, index, reason, html) {
    var row1 = $('table[id=tablequeue] > tbody > tr[data-neatupload-rowname=' + index + ']');
    var row2 = $('table[id=tablequeue] > tbody > tr[data-neatupload-rowprog=' + index + ']');
    if (reason == "canceled") {
        row1.removeClass("uploadItem-uploading").addClass("uploadItem-canceled");
        row2.removeClass("uploadItem-uploading").addClass("uploadItem-canceled");
        $('div.progress-bar', row2).width("100%");
    }
    $("td.cancel", row2).html("<span>" + reason + "</span>");
}
<div>
    <table width="100%" class="uploadItem" id="tablequeue">
        <tbody>
        </tbody>
    </table>
</div>

The first this I remark here is the css inclusion, of course for achieve nice things it’s necessary a good inspiration, which I don’t have, I confess it, but something not so ugly it’s done with the css provided in the example, as usually you’re free to play with it.
Here is the same function we’ve overridden in last scenario, fnAddFile, which is executed right after the user clicks the button Add. The main idea with that amount of code is create tow table row for each file in the queue, the first for show the file name and the second the progress and the cancel element, previously discussed. Please note, we have used the internal function to create the cancel element whatever to be its implementation (overridden or default).
The function fnShowStatus this time with a little jquery magic finds the progress element and updates its width instead of write directly the percent value. Finally the function fnRemoveFile ad you can guess is responsible of remove the rows involved with the file to be removed, as an apart the parameters for this function: plugin is a reference to the plugin as usually, index is the identifier related to the current file in the queue, reason is a string indicating the reason of removing the current file (canceled or completed) and the html parameter give us the data returned by the server after finished the work. In this case we have checked if the reason is canceled then fill the width and a different color in the progress bar for tell to the user that that upload did not success.
At the end of the example we find a div with a table inside and this table has an id = tablequeue and an empty tbody, this is the placeholder for the rows created in runtime by the code previously explained.

Scenario 6 – Validating data before to perform the upload.

Sometimes we have a form with some data and the upload can be performed only if the form is consistent with some rules and even attach some data, but I let this for the next scenario. For verify these rules I understand (and I think you too) to validate the input fields. Surprisingly I’ve anticipated this kind of behavior and there is a function that may be overridden whose name is fnValidate and receives a plugin object reference as parameter. Inside this function body you are able to use any validation engine such as jquery.validate or whatever you want, for didactic purposes I just made a very simple validation.
(...)
fnValidate: function (plugin) {
    var valid = $("#name").val() && $("#age").val();
    if (!valid) alert("Incorrect Data!");
    return valid;
}
(...)
<div>
    <label for="name">Name</label>
    <input id="name" name="name" type="text" value="" />
</div>
<div>
    <label for="age">Age</label>
    <input id="age" name="age" type="text" value="" />
</div>

As you can see, all I’ve done is test if the value of the name and age fields are not empty, in case of at least one of them is empty an alert box is shown. The rest of the plugin expects if you override this function to return true if everything is ok and false if there is something wrong with the input data.

Scenario 7 – Start upload immediately.

Sometimes we have to send some data to the server attached to the file, for example metadata associated to the file being uploaded, for solve this issue we can make a little trick in the fnAddFile function before send the data. We can gather the data and helping with the JSON object which is capable of serialize any JavaScript object into a string, and then that string is added to the form that actually send to file to the server. Remember that each file sent to the server is an actual POST with an actual form. In this case that form is received by parameter and it’s simply to create a new element, the ideal form field is the hidden field for this task and that’s what I do in the following code.
fnAddFile: function (plugin, filename, form, index) {
    var name = $("input[id=name]").val();
    var age = $("input[id=age]").val();
    $("input[id=name]").val("");
    $("input[id=age]").val("");
    var data = JSON.stringify({ name: name, age: age });
    $("<input type='hidden' name='filedata' value='" + data + "' />")
         .appendTo(form);
},
fnRemoveFile: function (plugin, index, reason, html) {
    alert(html);
}

@Html.Hidden("upload-action", Url.Action("UploadFileExtraData"))

The function fnRemoveFile that we used in the previous scenario, this time just show up with an alert box the html parameter, with the data returned by the server in the controller action that receives the post with the files. Please note here that I show the hidden field which saves that action, and note that is different than the previous scenarios, this time there’s something to do also in server side.
[HttpPost]
public ActionResult UploadFileExtraData(FormCollection collection)
{
    var tempPath = Server.MapPath("~/_temp_upload/");
    var value = string.Empty;
    for (var i = 0; i < UploadModule.Files.Count; i++)
    {
        value = UploadModule.Files[i].FileName;
        UploadModule.Files[i].SaveAs(tempPath + value);
        var data = collection["filedata"];
        var serializer = new JavaScriptSerializer();
        var deserializeObject = (Dictionary<string, object>)serializer.DeserializeObject(data);
        var name = (string)deserializeObject["name"];
        var age = (string)deserializeObject["age"];
        value = "Name = " + name + ", Age = " + age;
    }
    return Content(value);
}
I just show the controller action code (sorry webforms people, but don’t worry it’s the same in essence), this time there is a bit more of code in server side than previously. First thing new is to get from the collection, well it’s the same that take it from Request.Form[“…”], the important thing here is that we follow a convention the name filedata must match with the name we gave to the hidden field we created on the fly in fnAddFile and that’s why I marked in yellow background. The rest is simply deseralize it with the .NET powerful tools for that and finally store in the variable value the demonstrative string with the values extracted from the metadata and returned to the client.
Well, I think it’s all for the moment regarding the jquery.neatupload plugin. I hope this information to be useful for you. Any comment, feedback or even suggestion for improve it will be welcome. I’ll come back with some ASP.NET MVC 3 tricky features soon.
So Happy New Year to every one!

No comments:

Post a Comment