克隆不克隆选择值


77

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

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

这是正确的吗?

Answers:


76

经过进一步研究,我在JQuery Bug Tracker系统中找到了该票证,该票证解释了该错误并提供了解决方法。显然,克隆选择值太昂贵了,因此它们无法解决。

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

我对clone方法的使用是在通用方法中,在该方法中可能会克隆任何内容,因此我不确定何时或是否可以选择将其设置为on。因此,我添加了以下内容:

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

13
他们没有解释为什么它“太贵”。令我惊讶的是8年后没有更好的解决方案。
泰勒·科利尔

1
为什么不只看着选择更改并html selected在任何更改上添加属性,以便轻松克隆它呢?
亚当·彼得拉西亚克

针对IE的Bug票证投诉(固定网址:bugs.jquery.com/ticket/1294),但它在任何地方都无法正常工作。通过以下小提琴测试您的浏览器:jsfiddle.net/ygmL0k8m/4
hejdav

此修复程序不适用于我。以下答案(Novalis')有效。
rigdonmr

36

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

1
+1那是一个很棒的插件。请继续维护该项目。
Houman

2
这很棒!为什么jQuery不能做到这一点,开发人员正在使用Clone理解它的昂贵……但是我们需要以任何方式来做到这一点。谢谢,此修复程序很好用!+啤酒
Piotr Kula 2015年

有人可以解释如何应用吗?例如,在$('.inputPrefixListIx:first').clone().insertAfter('.inputPrefixListIx:last');考虑时应该如何jQuery.fn.clone
nskalis

不能选择多个。它只会选择第一个选项((((
–СергейСергеев20年

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

仅对其进行了简短测试,但它似乎可以正常工作。


6

我的方法有些不同。

我不会在克隆过程中修改选择,而只是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
});

现在,您可以按任意方式复制选择内容,它也会复制其值。

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

我认为此解决方案的自定义性较差,因此您无需担心以后再进行修改时代码是否会中断。

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

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

我以为这种方法很聪明,所以我几乎使用了它-但是,最终我意识到它违背了“ selected”属性的精神,因为它代表了初始值(默认值),因此实际上并没有改变<select>元素。资料来源:api.jquery.com/prop
etipton'2

改变它的不利之处是什么?即。变化initial selection
亚当·彼得拉西亚克

实际上,我想不出任何真正的TBH缺点。只是指出,从技术上讲,它违反了W3C规范。但不是主要的方法(因此仍然是一个不错的解决方案)。
etipton


2

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

尝试以下方法:

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

如果您真的对val函数的工作方式感兴趣,则可能需要检查一下

alert($.fn.val)

如果在选择对象上使用val(),则测试也会失败:test(“克隆应保留select的值”,function(){var select = $(“ <select>”)。append($(“ < option>“)。val(” 1“))。append($(” <option>“)。val(” 2“)); $(select).val(” 2“);等于($(select) .val(),“ 2”,“ expect 2”); var cl
Chief09

这很奇怪,因为这在IE 6/7,Firefox 3和Opera 9中对我有效。您的“等于”功能可能有问题吗?alert(eval('select = $(“ <select>”)。append($(“ <option>”)。val(“ 1”))。append($(“ <option>”)。val(“ 2 “)); $(select).val(” 2“); $(select).val()'));
user123444555621 2009年

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


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

});

0

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

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

0

经过一小时的尝试,不同的解决方案均无效,我确实创建了这个简单的解决方案

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

0

@ pie6k显示一个好主意。

它解决了我的问题。我将其更改为小一点:

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

0

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

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.