Клон не клонирует выбранные значения - PullRequest
66 голосов
/ 13 апреля 2009

Я не ожидал, но следующий тест не пройден при проверке клонированного значения:

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

Это правильно?

Ответы [ 10 ]

69 голосов
/ 13 апреля 2009

После дальнейших исследований я нашел этот билет в системе отслеживания ошибок JQuery, которая объясняет ошибку и предоставляет обходной путь. Очевидно, что клонировать выбранные значения слишком дорого, чтобы они не исправили это.

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());
});
27 голосов
/ 04 августа 2012

Вот исправленная версия метода клонирования для 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);
8 голосов
/ 16 июля 2011

Сделал плагин из ответа 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 голосов
/ 25 марта 2016

Мой подход немного другой.

Вместо того, чтобы изменять селекты во время клонирования, я просто наблюдаю за каждым 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
});

И теперь вы можете копировать select любым удобным для вас способом, и его значение тоже будет скопировано.

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

Я думаю, что это решение менее нестандартное , поэтому вам не нужно беспокоиться, если ваш код сломается, если вы что-то измените позже.

Если вы не хотите, чтобы он применялся к каждому выбору на странице, вы можете изменить селектор в первой строке, например:

$(document).on("change", "select.select-to-watch", function(){
2 голосов
/ 04 августа 2014

Упрощение ответа главного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

2 голосов
/ 17 августа 2011

При клонировании <select> не копируется свойство value= в <option> s. Поэтому плагин Марка работает не во всех случаях.

Чтобы исправить, сделайте это перед клонированием значений <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.

2 голосов
/ 13 апреля 2009

Да. Это , потому что свойство selected из узла DOM «select» отличается от атрибута selected из опций. jQuery никоим образом не изменяет атрибуты параметров.

Попробуйте вместо этого:

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

Если вы действительно заинтересованы в том, как работает функция val, вы можете изучить

alert($.fn.val)
0 голосов
/ 29 июля 2017

@ pie6k покажет хорошую идею.

Это решило мою проблему. Я немного изменил это:

$(document).on("change", "select", function(){
    var val = $(this).val();
    $(this).find("option[value=" + val + "]").attr("selected",true);
});
0 голосов
/ 27 ноября 2015

После 1 часа пробования различных неработающих решений я создал это простое решение

$clonedItem.find('select option').removeAttr('selected');
$clonedItem.find('select option[value="' + $originaItem.find('select').val() + '"]').attr('selected', 'true');
0 голосов
/ 28 января 2015

Если вам просто нужно значение select, чтобы сериализовать форму или что-то в этом роде, это работает для меня:

$clonedForm.find('theselect').val($origForm.find('theselect').val());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...