jQuery: IE8 bug when adding a Form
Quick version
I found a bug in IE8 when adding a form to the DOM using jQuery, fortunately there is a simple solution, unfortunately it took a while to stumble upon it.
Background
Whilst implementing a new in-page contact form for limethinking.co.uk I ran into a bug with Internet Explorer 8. Unexpectedly though it worked absolutely fine in IE 6 and 7, which does not happen very often so not working in 8 came as a rather unpleasant surprise.
The background is that the HTML for the new in-page contact form is fetched using Ajax so that a security token can be generated for it rather than it being part of the static HTML, it is not wanted for non-JavaScript users either who get the normal contact page. I was using jQuery to make the Ajax request and to append the returned HTML to the document using code similar to this simplified version:
$.get('/contact-us/ajax/', function(data)
{
$('body').prepend($(data).html());
}
The form was being added fine and its submit action called fine in Firefox, so I tested in the IEs, against expectations it was fine in 6 and 7 but in IE 8 the form was not displaying correctly, this appeared to be a quickly remedied CSS bug, but then rather less easy to fix the submit action would not work. After a few puzzling attempts at trying to work out why not I discovered that the HTML inserted in IE8 looked like this simplified version:
<form method="post" action="/url/"></form>
<fieldset>
<!--Form fields-->
</fieldset>
When it should have looked like this (and did in other browsers):
<form method="post" action="/url/">
<fieldset>
<!--Form fields-->
</fieldset>
</form>
The problem
So in IE8 the form was self closing. So why was this happening? By asking for the actual HTML being inserted I found the following in IE:
<FORM method=post action=/url/>
<FIELDSET>
<!--Form fields-->
</FIELDSET>
</FORM>
The above is the output using jQuery's html()
function which whilst more than just a wrapper for innerHTML does use innerHTML. So the problem is IE8's innerHTML function's mangling of the HTML. Specifically the quotes around the form's action attribute are being removed, because the action URL ends with a forward slash IE is then confusing action=/url/>
with action=/url />
and closing the form prematurely. Whilst IE8 changing the HTML for internal use with the innerHTML function is not in itself a bug, the ambiguity created and its inability to handle it surely is.
There is no direct way of controlling IE's removal of the attribute quotes, it does not happen for all attributes though, non-standard attributes retain theirs, as do attributes values containing whitespace. Of most note here is that this is not an issue for href attributes so the same problem does not arise when adding a elements, which suggests that the IE developers were aware of the potential problem.
I can see some logic to this, URLs ending with forward slashes are traditionally directories which you may well link to but would not submit a form to but the standard practice of omitting file extensions and using directory like structures for all pages pre-dates IE8 quite considerably and this was not an issue with earlier IE incarnations.
Possible Solutions
Rearrange the attribute order
As it happened the action attribute was the last listed in the source HTML, my immediate thought was just to move it before the others and sidestep the issue. This did not work as the order was just rearranged so that it came last. A little bit of experimentation confirmed that whilst the reordering was consistently the same it was not in an obvious order such as alphabetical or reverse alphabetical, the only attribute I could find which would come after the action attribute were non-standard attributes which were always placed last.
Introducing a non-standard, otherwise useless, attribute did not seem like an ideal solution and anyway Microsoft themselves point out that the ordering cannot be relied on to stay consistent throughout the lifetime of IE8.
Change the URL
A very simple solution is of course just to change the URL the form is submitted to to not have a forward slash at the end. This is of course perfectly fine in this case but I did not want to be changing the URL structure on any site that has a large number of forms added this way so wanted to find a more suitable solution.
Use an innerHTML replacement
There are a number of userland innerHTML replacements which would avoid this issue. I want to continue to use jQuery though and it uses innerHTML for quite a lot of DOM manipulation functions.
Just insert the jQuery object into the DOM
It turns out that just passing the jQuery object without calling html()
on it will give the required results, the HTML is inserted into the DOM without the problem occurring. Unfortunately for me I only realised this when I was creating a function to strip out add trailing forward slashes from action attributes and add them back in after inserting the form into the DOM. I decided to store the original actions using jQuery's data()
function, in order to retain this info I switched from inserting the results of $(data).html()
to just $(data)
so that the stored data would be retained at which point it turned out that this change alone was enough to fix it.