This SSCCE says it all:
<!doctype html>
<html lang="en">
<head>
<title>Test</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('#add').click(function() {
var ul = $('#ul');
var liclone = ul.find('li:last').clone(true);
var input = liclone.find('input');
input.attr('name', input.attr('name').replace(/(foo\[)(\d+)(\])/, function(f, p1, p2, p3) {
return p1 + (parseInt(p2) + 1) + p3;
}));
liclone.appendTo(ul);
$('#showsource').text(ul.html());
});
});
</script>
</head>
<body>
<ul id="ul">
<li><input type="text" name="foo[0]"></li>
</ul>
<button id="add">Add</button>
<pre id="showsource"></pre>
</body>
</html>
Copy'n'paste'n'run it, click the Add
button several times. On every click you should see the HTML code of the <ul>
to show up in the <pre id="showsource">
and the expected code should roughly be:
<li><input name="foo[0]" type="text"></li>
<li><input name="foo[1]" type="text"></li>
<li><input name="foo[2]" type="text"></li>
<li><input name="foo[3]" type="text"></li>
This works as expected in FF, Chrome, Safari, Opera and IE8.
However, IE6/7 fails in changing the name
attribute and produces like:
<li><input name="foo[0]" type="text">
<li><input name="foo[0]" type="text">
<li><input name="foo[0]" type="text">
<li><input name="foo[0]" type="text"></li>
I googled a bit and found this very similar problem, he fixed it and posted a code snippet how it should have look like. Unfortunately this is exactly what I already have done, so I suspect that he was only testing in IE8, not in IE6/7. Other than that particular topic Google didn't reveal much.
Any insights? Or do I really have to grab back to document.createElement
?
Note: I know that I can use just the same name for each input element and retrieve them as an array, but the above is just a basic example, in real I really need to have the name attribute changed, because it not only contains the index, but also other information such as parentindex, ordering, etc. It's been used to add/rearrange/remove (sub)menu items.
Edit: this is related to this bug, The jQuery (I'm using 1.3.2) does thus not seem to create inputs that way? The following does just work:
$('#add').click(function() {
var ul = $('#ul');
var liclone = ul.find('li:last').clone(true);
var oldinput = liclone.find('input');
var name = oldinput.attr('name').replace(/(foo\[)(\d+)(\])/, function(f, p1, p2, p3) {
return p1 + (parseInt(p2) + 1) + p3;
});
var newinput = $('<input name="' + name + '">');
oldinput.replaceWith(newinput);
liclone.appendTo(ul);
$('#showsource').text(ul.html());
});
But I can't imagine that I am the only one who encountered this problem with jQuery. Even a simple $('<input>').attr('name', 'foo')
doesn't work in IE6/7. Isn't jQuery as being a crossbrowser library supposed to cover this particular issue under the hoods?
Here is a function that will set the name of an element in all browsers, even IE6 and IE7. It is adapted from the code at http://matts411.com/post/setting_the_name_attribute_in_ie_dom.
function setElementName(elems, name) {
if ($.browser.msie === true){
$(elems).each(function() {
this.mergeAttributes(document.createElement("<input name='" + name + "'/>"), false);
});
} else {
$(elems).attr('name', name);
}
}
I found that using replaceElement and outerHTML was not reliable across different versions of IE. But the mergeAttributes trick above works perfectly!