Over a million developers have joined DZone.

File upload and Progress events with HTML5 XmlHttpRequest Level 2

· Web Dev Zone

Start coding today to experience the powerful engine that drives data application’s development, brought to you in partnership with Qlik.

The XmlHttpRequest Level 2 specification adds several enhancements to the XmlHttpRequest object. Last week I had blogged about cross-origin-requests and how it is different from Flash\Silverlight's approach.  With Level 2 specification one can upload the file to the server by passing the file object to the send method. In this post I'll try to explore uploading file using XmlHttpRequest 2 in conjunction with the progress events. I'll also provide a description on the new HTML5 tag - progress which can be updated while the file is being uploaded to the server. And of course, some ColdFusion code that will show how the file is accepted and stored on the server directory.


Progress Tag:

HTML5 has introduced several new elements to the language and one of them the progress element. This element is used to show a progress bar on the web page. This tag comes handy for describing any work in progress. It can be used to describe the progress of a time consuming task.The progress element comes with two attributes: value and max. The value attribute is used to indicate the current value of progress and the max attribute is used to describe completion value.

 <progress id="progressBar" value="0" max="100">  
 </progress>  

XmlHttpRequest Progress Events:

The only event listener that was available with XmlHttpRequest was the readystatechange event listener. Now with the advent of HTML5, several event listeners have been added to the XmlHttpRequest Interface - loadstart, progress, load, abort, error, timeout and loadend. The loadstart event is triggered when the request is initiated by the client. The progress event is triggered once the loadstart event has been dispatched.

In this example, I'll try to upload a file (text, image, mp3) using XmlHttpRequest and show the progress for the same by updating the progressbar (progress tag) using the progress event handler. With Level 2 specification one can now pass ArrayBuffer, Blob, File and FormData objects to the send method.

The input tag with the type file can be used to select a file that needs to be uploaded to the server (<input type="file" id="fileUpload">). Once the file is selected, a POST request can then be made to the server and the file object can be passed as an argument to the send method:

 function uploadFile(){  
         var filesToBeUploaded = document.getElementById("fileControl");  
         var file = filesToBeUploaded.files[0];  
         var xhrObj = new XMLHttpRequest();  
         xhrObj.upload.addEventListener("loadstart", loadStartFunction, false);  
         xhrObj.upload.addEventListener("progress", progressFunction, false);  
         xhrObj.upload.addEventListener("load", transferCompleteFunction, false);  
         xhrObj.open("POST", "upload.cfm", true);  
         xhrObj.setRequestHeader("Content-type", file.type);  
         xhrObj.setRequestHeader("X_FILE_NAME", file.name);  
         xhrObj.send(file);  
 }  

As observed in the above code, event listeners are added for loadstart, progress and load events. These events are added for the upload attribute of XmlHttpRequest object. The Content-type header is set to the value of file.type. This is required to let the server know the mime type of file being transferred. Also, the header X_FILE_NAME with the value of file.name is specified. The file object is then passed to the send method of the XmlHttpRequest object.

The loadstart event is triggered once a request to send a file to the server is initiated. Once this function has been dispatched the progress event is triggered indicating that the file is being uploaded to the server:

  function progressFunction(evt){  
         var progressBar = document.getElementById("progressBar");  
         var percentageDiv = document.getElementById("percentageCalc");  
         if (evt.lengthComputable) {  
           progressBar.max = evt.total;  
           progressBar.value = evt.loaded;  
           percentageDiv.innerHTML = Math.round(evt.loaded / evt.total * 100) + "%";  
         }  
 }  

The progress event is triggered as and when some data is uploaded to the server. This depends on the size of file that is being transmitted. The progressFunction defined above, takes an argument of type ProgressEvent. The ProgressEvent Interface defines the attributes - lengthcomputable, loaded and total. The lengthcomputable attribute is used to find whether the progress is an indeterministic or deterministic one. In this case the size of the file being uploaded is known and hence the lengthcomputable attribute will be set to true. The other attributes loaded and total are used to indicate the number of bytes uploaded of the total number of bytes. This data is then used to update the progress tag attributes value and max.

Server side code:

The server-side code is as simple as it can get:

 <cfset headerData = getHTTPRequestData().headers>  
 <cfset content = getHTTPRequestData().content>  
 <cfset filePath = expandPath(".") & "/Uploaded/" & headerData.X_FILE_NAME >  
 <cfset fileWrite(filePath,content)>  

The header X_FILE_NAME would contain the name of the file that is being sent from the client. The file content is available in the request data and the same is accessed using getHTTPRequestData().content.

Create data driven applications in Qlik’s free and easy to use coding environment, brought to you in partnership with Qlik.

Topics:

Published at DZone with permission of Sagar Ganatra, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}