克隆不是克隆选择值

时间:2009-04-13 01:35:28

标签: jquery

我没想到,但是以下测试在克隆值检查上失败了:

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");
});

这是对的吗?

12 个答案:

答案 0 :(得分:69)

经过进一步研究后,我在JQuery bug跟踪系统中找到了这张票,它解释了这个bug并提供了解决方法。显然,克隆选择值太昂贵,所以他们不会修复它。

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

我对克隆方法的使用是在通用方法中,任何可能克隆的东西,所以我不确定何时或是否会有一个选择来设置值。所以我添加了以下内容:

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

答案 1 :(得分:27)

这是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);

答案 2 :(得分:8)

从Chief7的回答中做了一个插件:

(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);

仅对其进行了简要测试,但似乎有效。

答案 3 :(得分:3)

我的方法略有不同。

我没有在克隆过程中修改选择,而只是在select页上查看每个change事件,然后,如果值已更改,我需要添加所需的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(){

答案 4 :(得分:2)

是。这是because'select'DOM节点的'selected'属性与选项的'selected'属性不同。 jQuery不会以任何方式修改选项的属性。

请改为尝试:

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

如果你真的对val函数的工作原理感兴趣,你可能想要检查

alert($.fn.val)

答案 5 :(得分:2)

克隆<select> 复制value=上的<option>属性。所以Mark的插件并不适用于所有情况。

要修复,请在克隆<select>值之前执行

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

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

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

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

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

答案 6 :(得分:2)

简化chief7的回答:

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

答案 7 :(得分:0)

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

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

答案 8 :(得分:0)

在尝试了不同的解决方案1小时后,我确实创建了这个简单的解决方案

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

答案 9 :(得分:0)

@ pie6k显示了一个好主意。

它解决了我的问题。我把它改成一点点:

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

答案 10 :(得分:0)

$(document).on("change", "select", function(){
    original = $("#original");
    clone = $(original.clone());
    clone.find("select").val(original.find("select").val());

});

答案 11 :(得分:0)

只报告回来。由于某些不为人知的原因,即使这是我测试的第一件事,而且我也没有更改代码,现在是

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

方法正在起作用。我不知道为什么或一旦更改某些内容它是否会再次停止工作,但是我现在就继续讨论。谢谢大家的帮助!