Upload Files Asynchronously

Tagged:  

You are familiar with Ajax and I'm sure that you've used it (or seen it used) in many applications. Of course Ajax is used to transfer data through XML or JSON (or plain text) so the data is never binary data. However, what if you are making an application that needs to be able to upload a binary file asynchronously? Well I've run across an interesting article that explains how to accomplish this.

The article has updated code from the initially released code. Below is the initial code.

Source code for index.html   (Download source code)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Iframe Ajax</title>
    <script type="text/javascript" src="webtoolkit.aim.js"></script>

    <script type="text/javascript">
        function startCallback() {
            // make something useful before submit (onStart)
            return true;
        }

        function completeCallback(response) {
            // make something useful after (onComplete)
            document.getElementById('nr').innerHTML = parseInt(document.getElementById('nr').innerHTML) + 1;
            document.getElementById('r').innerHTML = response;

        }
    </script>
</head>

<body>

    <form action="index.php" method="post" onsubmit="return AIM.submit(this, {'onStart' : startCallback, 'onComplete' : completeCallback})">

        <div><label>Name:</label> <input type="text" name="form[name]" /></div>
        <div><label>File:</label> <input type="file" name="form[file]" /></div>

        <div><input type="submit" value="SUBMIT" /></div>
    </form>

    <hr/>

    <div># of submited forms: <span id="nr">0</span></div>

    <div>last submit response (generated by form action - index.php file): <pre id="r"></pre></div>

</body>
</html>

Source code for webtoolkit.aim.js   (Download source code)

/**
*
*  AJAX IFRAME METHOD (AIM)
*  http://www.webtoolkit.info/
*
**/

AIM = {

    frame : function(c) {

        var n = 'f' + Math.floor(Math.random() * 99999);
        var d = document.createElement('DIV');

        d.innerHTML = '<iframe style="display:none" src="about:blank" id="'+n+'" name="'+n+'" onload="AIM.loaded(\''+n+'\')"></iframe>';

        document.body.appendChild(d);

        var i = document.getElementById(n);
        if (c && typeof(c.onComplete) == 'function') {
            i.onComplete = c.onComplete;
        }

        return n;
    },

    form : function(f, name) {
        f.setAttribute('target', name);
    },

    submit : function(f, c) {

        AIM.form(f, AIM.frame(c));
        if (c && typeof(c.onStart) == 'function') {
            return c.onStart();
        } else {
            return true;
        }
    },

    loaded : function(id) {
        var i = document.getElementById(id);
        if (i.contentDocument) {
            var d = i.contentDocument;
        } else if (i.contentWindow) {
            var d = i.contentWindow.document;

        } else {
            var d = window.frames[id].document;
        }
        if (d.location.href == "about:blank") {
            return;
        }

        if (typeof(i.onComplete) == 'function') {
            i.onComplete(d.body.innerHTML);
        }
    }

}

You can see the demo of the code here.

Below is an excerpt (including the code) from the updated post.

How to upload files asynchronously?

As I described above You can’t upload files using AJAX. Some time ago I wrote a JavaScript file upload object which as You already understood can help developers make forms which upload files asynchronously.

Today I made some modifications to this code and I want You to try it. Its simple, really fast to implement. Just paste this code into your document or external JavaScript (ajaxupload.js) file:

AsyncUpload = {
 
	createFrame : function(formElement, completeCallback) {
		var frameName = 'f' + Math.floor(Math.random() * 99999);
		var divElement = document.createElement('DIV');
		divElement.innerHTML = '<iframe style="display:none" src="about:blank" id="'+frameName+'" name="'+frameName+'" onload="AsyncUpload.documentLoaded(\''+frameName+'\')"></iframe>';
		document.body.appendChild(divElement);

 
		var frameElement = document.getElementById(frameName);
		if (completeCallback && typeof(completeCallback) == 'function') {

			frameElement.completeCallback = completeCallback;
		}
		formElement.setAttribute('target', frameName);
	},
 
	documentLoaded : function(elementID) {

		var frameElement = document.getElementById(elementID);
		if (frameElement.contentDocument) {
			var documentElement = frameElement.contentDocument;
		} else if (frameElement.contentWindow) {

			var documentElement = frameElement.contentWindow.document;
		} else {
			var documentElement = window.frames[elementID].document;
		}

		if (documentElement.location.href == "about:blank") {
			return;
        }
		if (typeof(frameElement.completeCallback) == 'function') {

			frameElement.completeCallback(documentElement.body.innerHTML);
		}
	},
 
	submitForm : function(formElement, startCallback, completeCallback) {

		AsyncUpload.createFrame(formElement, completeCallback);
		if (startCallback && typeof(startCallback) == 'function') {
			return startCallback();
		} else {

			return true;
		}
	}
 
}

Now write your xHTML document (index.html). Let say it will look like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

    <title>Asynchronous Upload</title>
    <script type="text/javascript" src="ajaxupload.js"></script>

    <script type="text/javascript">
        function startCallback() {
            return true;
        }
 
        function completeCallback(response) {
            obj = eval('('+response+')');
            alert(obj.firstname);
            document.getElementById('r').innerHTML = response;
        }
    </script>
</head>
 

<body>
 
    <form action="index.php" method="post" enctype="multipart/form-data" onsubmit="return AsyncUpload.submitForm(this, startCallback, completeCallback)">

        <div><label>First name:</label> <input type="text" name="firstname" /></div>

        <div><label>Last name:</label> <input type="text" name="lastname" /></div>

        <div><label>CV:</label> <input type="file" name="cv" /></div>

        <div><input type="submit" value="SUBMIT" /></div>
    </form>

 
    <p>Response: <span id="r"></span></p>
 
</body>
</html>

On backend (web server) i wrote this PHP script (index.php):

<?php
echo json_encode(
	array_merge(
		$_REQUEST,
		$_FILES

	)
);
?>

Now You must fill the form (firstname, lastname and attach CV file) to test it. When You submit the form, the current page won’t reload. This script will load the index.php file in the background (CV file will be sent in the background too). PHP script will output JSON (about this technology maybe some other time) encoded string.

In the index.html file function completeCallback will handle the index.php response without reloading the page. Voila! Now You only need to figure it out where You can use this JavaScript Asynchronous File Upload Object.

You can read the full post here.

You can download the full source code here.

This is a very interesting use of sending data asynchronously. I never would have thought to use frames in the way that the code does in order to upload the file. I would love to hear if you find any good uses for this code. You can leave them in the comments or write a complete blog post on this blog using your free Ajaxonomy account.

The initial source code was originally posted on webtoolkit.info

[...] Upload Files Asynchronously By David Hurth Source code for webtoolkit.aim.js (Download source code). /** * * AJAX IFRAME METHOD (AIM) * http://www.webtoolkit.info/ * **/ AIM = { frame : function(c) { var n = 'f' + Math.floor(Math.random() * 99999); … Ajaxonomy - The Study of Ajax… - http://www.ajaxonomy.com [...]

you must close this tag

Nice job making the original code more readable. It's going into my demo webpage soon, I hope. I assume this works in Safari as well?

PS, maybe it's just me, but your captcha is quite hard to read.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <pre> <div> <blockquote> <object> <embed> <img> <param>
  • Lines and paragraphs break automatically.
  • Web page addresses and e-mail addresses turn into links automatically.

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
Copy the characters (respecting upper/lower case) from the image.