jQuery clone problem
I am trying to clone a div and change the names of the input fields in this div. It works great for most of the browsers but IE 7 does not change the name attribute of the input fields.
Demo: http://jsbin.com/iduro/7
HTML
<body>
<pre></pre>
<div><input value="Hello World" name="test"></div>
</body>
JS
var lastRow = $("body div:last"),
newRow = lastRow.clone(true)
.show()
.insertAfter(lastRow);
newRow.find('input').attr("name","test2");
$("pre").text( newRow[0].innerHTML );
Results:
Firefox: (works)
<input value="Hello World" name="test2"&开发者_StackOverflowgt;
IE8 (works)
<INPUT value="Hello World" name=test2 jQuery1273063250500="4">
IE7 (bug):
<INPUT value="Hello World" name=test jQuery1273063303968="4">
As you see the name of IE7 does not change to test2.
Is there any obvious reason or work around?
I could fix it for now. As long as an input field is not attached to the dom you can change the name and the radio buttons work properly again.
// Old Code
$("div:last").clone(true).children("input").attr("name","newName");
// New Code
$("div:last").clone(true).children("input").fixCloneBug ("newName");
To lower the execution time only the jQuery Events, the className and the type attribute are copied.
fixCloneBug Method:
(function( $ )
{
if ( ! $.browser.msie || parseInt( $.browser.version ) > 7 )
// NO FIX FOR IE 7+ FF WEBKIT
$.fn.fixCloneBug = function( newName ){ return this.attr( "name", newName ) };
else
// FIX IE 5-7
$.fn.fixCloneBug = function( newName )
{
var $cloned = $();
this.each(function( )
{
/* -._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._
Create a new element with className and jQuery events of the buggy element
*/
var $elem = $(this),
$newElem = $(document.createElement( $elem.attr('tagName') ));
// USE SAME TYPE
$newElem.attr('type', $elem.attr('type') );
// SET NAME
$newElem.attr('name', this.name );
$newElem.attr('name', newName );
// ADD TO DOM
$newElem.insertBefore( $elem );
// CLONE EVENTS
$newElem.data( "events", $elem.data("events") );
// CLASS NAME
$newElem.attr('className', this.className );
/* -._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._
Delete buggy element
*/
$elem.remove();
// Add to result
$cloned.push($newElem);
})
return $cloned;
}
}(jQuery));
Maybe you think $newElem.attr('name', this.name );
is useless however it allows me to use a jQuery 1.4 feature:
.fixCloneBug (function(i,oldname){ return oldname+"_new" })
try this ( raw code)
$(some_cloned_element).each(function(i, elem){
var newName = "yay_i_love_my_new_name";
if ($.browser.msie === true){ // evil browser sniffing *cries*
$(elem).replaceWith(document.createElement(
this.outerHTML.replace(/name=\w+/ig, 'name='+newName+'_'+i)
));
} else {
$(elem).attr('name',newName+'_'+i);
}
$("body").append(some_cloned_element);
});
check when i=50 and then break/exit
better way : use name as array like name=picture[]
Refernece
If you pan on accessing these as a set when the form is posted then there is no need to change the name - just dont put a value within the brackets and it will be incremented for you when you grab the array on the server side:
<input name="test[]" />
If you need to be able to access each one by index from js you can just use get
on the appropriate collection returned by a selector. Or you can assign ID attributes like test_1
.
The simple solution for Radio button is :
$("div:last").find("radio").each(function(){
var name="someNewName";
var id="someNewId";
if (!$.browser.msie || parseInt($.browser.version) > 7) {
this.name = name;
this.id=id;
}
else {
(this).attr("outerHTML", "<input type=radio id=" + id + " name=" + name + " />");
}
});
This will alter the outerHTML of the element so that the HTML for the element(radio button) is overwritten. The same solution can be applied for : find("input") / find("checkbox") for the other controls too.
精彩评论