克隆不是克隆选择值

我没有预料到这一点,但下面的测试在克隆值检查上失败了:

test("clone should retain values of select", function() {
var select = $("<select>").append($("<option>")
.val("1"))
.append($("<option>")
.val("2"));
$(select).val("2");
equals($(select).find("option:selected").val(), "2", "expect 2");
var clone = $(select).clone();
equals($(clone).find("option:selected").val(), "2", "expect 2");
});

是这样吗?

43904 次浏览

是的。这是 因为“ select”DOM 节点的“ select”属性与选项的“ select”属性不同。JQuery 不以任何方式修改选项的属性。

试试这个:

$('option', select).get(1).setAttribute('selected', 'selected');
//    starting from 0   ^

如果您真的对 val 函数的工作原理感兴趣,那么您可能想研究一下

alert($.fn.val)

经过进一步的研究,我在 JQuery bug 跟踪系统中找到了这张票据,它解释了 bug 并提供了一个解决方案。显然,克隆选择值的代价太高,以至于他们无法修复它。

Https://bugs.jquery.com/ticket/1294

我使用的克隆方法是在一个泛型方法中,任何东西都可能被克隆,所以我不确定什么时候或者是否会有一个 select 来设置值。所以我加了以下内容:

var selects = $(cloneSourceId).find("select");
$(selects).each(function(i) {
var select = this;
$(clone).find("select").eq(i).val($(select).val());
});

用酋长的回答做了个插件:

(function($,undefined) {
$.fn.cloneSelects = function(withDataAndEvents, deepWithDataAndEvents) {
var $clone = this.clone(withDataAndEvents, deepWithDataAndEvents);
var $origSelects = $('select', this);
var $clonedSelects = $('select', $clone);
$origSelects.each(function(i) {
$clonedSelects.eq(i).val($(this).val());
});
return $clone;
}
})(jQuery);

只是简单测试了一下,但似乎有效。

克隆一个 <select>会使 没有复制 <option>上的 value=属性,所以马克的插件并不是在所有情况下都能工作。

要解决这个问题,请执行 之前克隆 <select>值:

var $origOpts = $('option', this);
var $clonedOpts = $('option', $clone);
$origOpts.each(function(i) {
$clonedOpts.eq(i).val($(this).val());
});

在 jQuery 1.6.1 + 中,克隆选择哪个 <select>选项的另一种方法是..。

// instead of:
$clonedSelects.eq(i).val($(this).val());


// use this:
$clonedSelects.eq(i).prop('selectedIndex', $(this).prop('selectedIndex'));

后者允许您设置 <option>之后,设置 selectedIndex

下面是 jQuery 克隆方法的一个固定版本:

Https://github.com/spencertipping/jquery.fix.clone

// Textarea and select clone() bug workaround | Spencer Tipping
// Licensed under the terms of the MIT source code license


// Motivation.
// jQuery's clone() method works in most cases, but it fails to copy the value of textareas and select elements. This patch replaces jQuery's clone() method with a wrapper that fills in the
// values after the fact.


// An interesting error case submitted by Piotr Przybył: If two <select> options had the same value, the clone() method would select the wrong one in the cloned box. The fix, suggested by Piotr
// and implemented here, is to use the selectedIndex property on the <select> box itself rather than relying on jQuery's value-based val().


(function (original) {
jQuery.fn.clone = function () {
var result           = original.apply(this, arguments),
my_textareas     = this.find('textarea').add(this.filter('textarea')),
result_textareas = result.find('textarea').add(result.filter('textarea')),
my_selects       = this.find('select').add(this.filter('select')),
result_selects   = result.find('select').add(result.filter('select'));


for (var i = 0, l = my_textareas.length; i < l; ++i) $(result_textareas[i]).val($(my_textareas[i]).val());
for (var i = 0, l = my_selects.length;   i < l; ++i) result_selects[i].selectedIndex = my_selects[i].selectedIndex;


return result;
};
}) (jQuery.fn.clone);

首席执行官7的回答简化如下:

var cloned_form = original_form.clone()
original_form.find('select').each(function(i) {
cloned_form.find('select').eq(i).val($(this).val())
})

同样,这里是 jQuery 票据: http://bugs.jquery.com/ticket/1294

如果您只需要 select 的值来序列化表单或类似的东西,这对我很有用:

$clonedForm.find('theselect').val($origForm.find('theselect').val());

经过一个小时尝试不同的解决方案,没有工作,我确实创建了这个简单的解决方案

$clonedItem.find('select option').removeAttr('selected');
$clonedItem.find('select option[value="' + $originaItem.find('select').val() + '"]').attr('selected', 'true');

我的方法有点不同。

在克隆过程中,我没有修改选择,我只是观察页面上每个 selectchange事件,然后,如果值改变了,我将需要的 selected属性添加到选择的 <option>中,这样它就变成了 <option selected="selected">。由于选择现在标记在 <option>的标记中,当您将 .clone()它时,它将被通过。

你唯一需要的代码:

//when ANY select on page changes its value
$(document).on("change", "select", function(){
var val = $(this).val(); //get new value
//find selected option
$("option", this).removeAttr("selected").filter(function(){
return $(this).attr("value") == val;
}).first().attr("selected", "selected"); //add selected attribute to selected option
});

现在,你可以复制选择任何你想要的方式,它的值也会被复制。

$("#my-select").clone(); //will have selected value copied

我认为这个解决方案的 习俗更少,所以你不需要担心如果你的代码会中断,如果你稍后修改的东西。

如果您不希望它应用到页面上的每个选择,您可以在第一行更改选择器,如:

$(document).on("change", "select.select-to-watch", function(){

@ pie6k show a good idea.

它解决了我的问题,我把它改小一点:

$(document).on("change", "select", function(){
var val = $(this).val();
$(this).find("option[value=" + val + "]").attr("selected",true);
});
$(document).on("change", "select", function(){
original = $("#original");
clone = $(original.clone());
clone.find("select").val(original.find("select").val());


});

只是回来报告。由于一些神圣的未知原因,即使这是我测试的第一件事情,我没有改变我的代码无论如何,现在

$("#selectTipoIntervencion1").val($("#selectTipoIntervencion0").val());

方法奏效了。我不知道为什么,也不知道一旦我改变了什么,它是否还会继续工作,但是我现在要用这个。谢谢大家的帮助!