克隆不是克隆选择值

chi*_*ef7 72 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");
});
Run Code Online (Sandbox Code Playgroud)

这是正确的吗?

chi*_*ef7 70

经过进一步的研究,我在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());
});
Run Code Online (Sandbox Code Playgroud)

  • 他们没有解释为什么它"太贵".我很惊讶8年后没有更好的解决方案. (11认同)
  • 为什么不只监视选择的更改并在任何更改上添加“html”“selected”属性,以便轻松克隆它? (2认同)

Nov*_*lis 31

这是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);
Run Code Online (Sandbox Code Playgroud)

  • 不适用于选择多个。它只选择第一个选项 ((( (3认同)
  • 这很棒!为什么jQuery不能做到这一点,开发人员正在使用Clone理解它的昂贵……但是我们需要以任何方式来做到这一点。谢谢,此修复程序很棒!+啤酒 (2认同)

mpe*_*pen 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);
Run Code Online (Sandbox Code Playgroud)

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


pie*_*e6k 7

我的方法有点不同。

我没有在克隆期间修改选择,而是查看select页面上的每个change事件,然后,如果值发生更改,我将需要的selected属性添加到 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
});
Run Code Online (Sandbox Code Playgroud)

现在,您可以按照您想要的任何方式复制选择,并且它的值也会被复制。

$("#my-select").clone(); //will have selected value copied
Run Code Online (Sandbox Code Playgroud)

我认为此解决方案不太自定义,因此您无需担心如果您稍后修改某些内容,您的代码是否会中断。

如果您不想将其应用于页面上的每个选择,您可以在第一行更改选择器,例如:

$(document).on("change", "select.select-to-watch", function(){
Run Code Online (Sandbox Code Playgroud)


Col*_*son 5

Chief7的答案的简化:

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

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


use*_*621 2

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

试试这个:

$('option', select).get(1).setAttribute('selected', 'selected');
//    starting from 0   ^
Run Code Online (Sandbox Code Playgroud)

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

alert($.fn.val)
Run Code Online (Sandbox Code Playgroud)