Adding HTML control dynamically using jQuery

Introduction

We often need to add functionality in web pages by which HTML control can be added on the page at run time. To add pure HTML controls (especially in MVC applications) from Javascript code, we can effectively use jQuery functions.

Background

I found this question in many times in asp.net forum that, how to create functionality on client side code such that if there is single file upload control on the page, user can click on a button to create another file upload box and upload multiple documents together. I always find it easy to write a blog post about such repetitive questions rather than explaining in forums. In this short article, we would consider multiple file upload example.

Article Body

To undersand the jQuery feature of adding control on page at run time, we will consider file upload example. Suppose we have a file upload feature in the web application. The number of files that user could upload is not fixed hence, we cannot provide fix number of file upload controls. There is also possibility that user might upload single document hence, it is not logical to display many upload fields.

The solution could be what most of sites adopt, to show single file upload at start and provide “upload another file” button. When user clicks on it, another file upload control gets added in DOM of page and user can select another file to be uploaded. This can be repeated for multiple times.

We will now look into a demo application and the code. Lets create a new dummy project in Asp.net MVC (Although, the jQuery code of this demo can be used as it is in case of normal web site application).

I am going to use the existing default home controller and default Index.aspx. You may want to create the new controller and view.

Create a container div which will hold all file upload controls. This is in fact is the main container in which dynamically added input file controls will be added. The main container div will have another div inside that a input type file. Our basic structure of div and initial input file control will look like this

<div id="fileUploadContainer">
    <div id="uploadContainer1" style="height:30px">
        <input type="file" id="file1" name="file1"/>
    </div>
</div>

here, fileUploadContainer is the main container div while uploadContainer1 is the immediate enclosing div of input type file control file1. Please note that id and name of internal div and file control is intentionally contains number 1 so that the next added controls can be named as file2, file3 etc.

To complete the HTML, lets add file upload button and the link which will be used to create new file controls dynamically. As the form with file upload control needs to be “posted”, we will add HTML.BeginForm too. So, now our complete HTML would be

<% using (Html.BeginForm("FileUpload", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{%><br />
    <div id="fileUploadContainer">
        <div id="uploadContainer1" style="height:30px">
            <input type="file" id="file1" name="file1"/>
        </div>
    </div>
    <input type="submit" value="Upload File" />
    <a id="btnAdd" href="#">Add another file </a>
    <div id="result"></div>
<% } %>

On click of link btnAdd, jQuery code needs to be called which will create file control. As per our html format of file upload control, there should be a div with which encloses file control and this div would finally added in main container div. So, we should first create html control in jQuery for internal div and file control.

var htmlFormatDiv = $("<div id='uploadContainer' style='height:30px'></div>");
var htmlFormatFile = $("<input type='file'/>");

Now, id and name field of div and file control is important. If same id is duplicated for multiple file controls then we would have trouble reading multiple documents on server side. To maintain uniqueness of control id’s, we will keep the file id/name as file1, file2, file3 etc. However, to decide this name, we require to determine how many controls are already added in the main container div.

The count of total div’s present inside main container div would give us the total number of file controls already added. This count can then be used to decide new file controls id and name

var totalFileCount = $("#fileUploadContainer").children("div").length;
htmlFormatFile.attr("id", "file" + (totalFileCount + 1));
htmlFormatFile.attr("name", "file" + (totalFileCount + 1));
htmlFormatDiv.attr("id", "uploadContainer" + (totalFileCount + 1));

At this stage, we have div and file control created and their id’s are updated properly. We just need to add file control in internal div and then this internal div into main container div.

htmlFormatDiv.append(htmlFormatFile);
$("#fileUploadContainer").append(htmlFormatDiv);

 

The complete code should be called on click on link so, lets bind this complete code in click event of link.

<script type="text/javascript">
    $(document).ready(function () {
        $('#btnAdd').click(function (e) {
            e.preventDefault();
            var htmlFormatDiv = $("<div id='uploadContainer' style='height:30px'></div>");
            var htmlFormatFile = $("<input type='file'/>");
            var totalFileCount = $("#fileUploadContainer").children("div").length;
            htmlFormatFile.attr("id", "file" + (totalFileCount + 1));
            htmlFormatFile.attr("name", "file" + (totalFileCount + 1));
            htmlFormatDiv.attr("id", "uploadContainer" + (totalFileCount + 1));
            htmlFormatDiv.append(htmlFormatFile);
            $("#fileUploadContainer").append(htmlFormatDiv);
        });
    });
</script>

 

Once the above Javascript and html code is complete, lets create action result FileUpload in home controller class. To test the uploaded files, I have created simple method which checks each file and if content is found in file control then increment the count. Finally plain content is displayed on page which shows total number of file controls which had file selected.

public ActionResult FileUpload()
        {
            int uploadCount = 0;
            foreach (string upload in Request.Files)
            {
                if (((HttpPostedFileBase)Request.Files[upload]).ContentLength > 0)
                {
                    uploadCount = uploadCount + 1;
                }
            }

            return Content("Total '" + uploadCount.ToString() + "' files were uploaded");
        }

Request.Files gives total number of file controls in the request. We need to check their ContentLength to make sure that the control actually contains file or it was blank.

Conclusion

The demo gives overview of file control. The method can be easily adopted to create different controls in HTML DOM at run time. The similler effect can also be achieved by using plain Javascript code instead of jQuery but jQuery makes it tremendously easy and clean to understand.