Sunday, April 19, 2015

Simplest file upload using JavaScript and iframe


       Uploading a file using web page needs the page to be submitted. There was no other way to do this except that HTML5 came up with the FileReader object.
But if you need a version of file upload that is asynchronous kind of like Ajax then here is a very simple solution.
      I’ve used ASP.NET with JavaScript the same concept and the JavaScript code can be used with any other server side processing language. Note that this uses only JavaScript and no jQuery and is browser independent (Iv’e checked this in IE8 and it works fine)
     A HTTP Handler is the one that handles file submission and returns a HTML string that is used to display a response.

The HTML code has a from with a file control and div tag to display the result
<body>
<form action='fileuploader.ashx' method="post" id='frmUpload' enctype="multipart/form-data" >
<input type="file" name="file1" onchange="fileUpload('upload'); return false;" />
<div id="upload"></div>
</body>

    The form is called frmupload & including the enctype="multipart/form-data"
is important to get the file data upon submission.  The file control is called file1 and the result div is called upload.



The .ashx.cs file contains the following code:
public void ProcessRequest(HttpContext context)
        {
            context.Response.AddHeader("Pragma", "no-cache");
            context.Response.AddHeader("Cache-Control", "private, no-cache");
            //only the post method is handled
            if (context.Request.HttpMethod == "POST")
            {
                try
                {
                    string fName = "";
                    if (context.Request.Files["file1"] != null)
                    {
                        if (!String.IsNullOrEmpty(context.Request.Files["file1"].FileName))
                        {
                            //get only the filename
                            fName = System.IO.Path.GetFileName(context.Request.Files["file1"].FileName);
                            //its better to use the SaveAs methof provided by the file upload control
                            //in later browers the FileName does not give the complete path of the file
                            //in ie8 the FileName gives the complete path
                            context.Request.Files["file1"].SaveAs(HttpContext.Current.Server.MapPath("uploads") + "/" + fName);
                                context.Response.Write(fName+" has been uploaded");
                        }
                        else
                        {
                            context.Response.Write("There was an error uploading the file");
                        }
                    }
                }
                catch
                {
                    context.Response.Write("There was an error uploading the file");
                }
            }
        }
If you see an ashx file, the main method put the by default by visual studio is the

 public void ProcessRequest(HttpContext context)

We will use this method to get our file using the HttpContext object provided by the method.

       This method takes the HttpContext object (called context) and uses it to get the file control.
The control has methoid called SaveAs that is used to save the file into a location on the server. While using IE (IE 8), I found that the FileName property of the control gives the complete path of the file from the client’s machine. Do Not use this, as newer browsers as well as newer IE does not display the complete path. The code above, gets the filename only and uses the SaveAs method to save the file.

The last part, and probably the important part is the JavaScript code :
function fileUpload(res) {
            document.getElementById(res).innerHTML = "Uploading……"
            var frm = document.getElementById('frmUpload');
            var iframe = document.createElement("iframe");
            iframe.setAttribute("id", "uploaderIframe");
            iframe.setAttribute("name", "uploaderIframe");
            iframe.setAttribute("style", "width: 0; height: 0; border: none;");
            frm.parentNode.appendChild(iframe);
            frame = document.getElementById("uploaderIframe");
            var eventHandler = function () {
                if (frame.contentDocument) {
                    data = frame.contentDocument.body.innerHTML;
                }
                //this line puts the content returned into the result div
                document.getElementById(res).innerHTML = data;
                setTimeout('frame.parentNode.removeChild(frame)', 100);
            }
            if (frame.addEventListener)
                frame.addEventListener("load", eventHandler, true);
            if (frame.attachEvent)
                frame.attachEvent("onload", eventHandler);
            frm.setAttribute("target", "uploaderIframe");
            frm.submit();
        }

      JavaScript is used to submit the form but before that we attach an iframe to it and post the form
The script creates an iframe, attaches the iframe to the form and submits the form. The reponse from the server is put into the div tag that displays the result.