Posting forms AJAX like

This article deals with the problems facing an AJAX like implementation of posting general form data.

Posting simple data asynchronously by using GET or POST or even more exotic methods can be done by using the XHR object or a good wrapper like jQuery. More complicated data like files could be tackled by using the new FileAPI. This is, however, at the moment a no-go due to backwards-compatibility. Therefore we could use a different way by posting the <form> into an <iframe> and reading out the contents of this document.

The following code gives a rough estimate of the principle:

<!DOCTYPE HTML>
<html>
<head>
<!-- ... -->
<body>
<!-- ... -->
<form method="POST" action="..." target="my_name">
<!-- Form data elements -->
</form>
<iframe name="my_name" id="my_id" style="display: none;"></iframe>
</html>

So far so good. This good should work in all major browsers even back to IE6 and such. However, if we want to generate the <iframe> by using JavaScript we have to face some obstacles. Why do we want to generate the <iframe> in JavaScript anyway? Well, usually all this AJAX stuff should generate a single-page experience. This will usually increase the usability of the page and generate a more user-friendly look. The website will also look more like a webapplication, generating the behavior of real applications. That said we look only at such asynchronous techniques (like AJAX) if JavaScript is enabled. Therefore the standard mode is kind of a fallback and JavaScript will eventually turn the page into an application.

Now let's do the <iframe> creation naively in JavaScript. We could write the following code:

var _iframe = document.createElement('iframe');
_iframe.setAttribute('name', 'my_name');

This does work very well in all browsers except Microsoft's IE. The <iframe> has a bug, which prevents the name attribute to be set by using the setAttribute() method. This is not a big problem since we could just use other methods. One possiblity is:

var _div = document.createElement('div');
_div.innerHTML = '<iframe name="my_name" style="display: none;"></iframe>';

If we do not want the additional <div> we could just abuse the createElement() method with more information or do the following (second way):

var _iframe = document.createElement('iframe');
_iframe.name = 'my_name';

This works like a charm and is also a quite often used practice for setting a single attribute of any DOM element. However, this was just a small problem. The biggest issue with using the whole <iframe> approach in combination with the Internet Explorer is reading out the data.

In order to read out the received data we have to be informed that the <iframe> has changed its content. Luckily the DOM already provides an event for that: onload. So let's just use that naively:

var _iframe = document.getElementById('my_id');//Let's suppose we gave our iframe that ID
_iframe.onload = function() {
     /* Here we can execute our code when the data has been received */
};

Now this works in every browser except IE. IE will still show that the onload event is not handled by our JavaScript code. Let's modify our initial static HTML code to look like the following:

<iframe onload="alert('Executed...');" name="my_name" id="my_id" style="display: none;"></iframe>

Using the snippet we are able to see that IE does now understand the onload event. When the event is triggered we see a message box popping up with the "Executed..." statement. Obviously IE has only a JavaScript event assignment bug. So what is the logical conclusion to do? We assign a method when creating the <iframe>, thus avoiding any reassignments to the event. All reassignments will be done by redefining the method itself.

Let's have a look at some example code:

window.callback = function(sender) {
     /* In order to avoid any errors we already extend the window object */
};
var _iframe = document.createElement('<iframe onload="callback(this);" name="my_name" id="my_id" style="display: none;"></iframe>');

If we need to reassign the callback method we can easily do that by just using the following code (again):

window.callback = function(sender) {
     /* This is a redefinition */
};

This concludes a very short introduction into posting forms asynchronously with the help of the <iframe> element. This bug (and some others) will hopefully vanish with the upcoming IE10.

Created .

References

Sharing is caring!