Клон не клонирует выбранные значения
Я этого не ожидал, но следующий тест не прошел проверку клонированной стоимости:
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");
});
Правильно ли это?
Ответы
Ответ 1
После дальнейших исследований я нашел этот билет в системе отслеживания ошибок 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());
});
Ответ 2
Здесь фиксированная версия метода clone для 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 clone() method works in most cases, but it fails to copy the value of textareas and select elements. This patch replaces jQuery 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 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);
Ответ 3
Сделал плагин из ответа 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);
Проверено только на короткое время, но, похоже, оно работает.
Ответ 4
Мой подход немного отличается.
Вместо того, чтобы изменять выбор во время клонирования, я просто просматриваю каждую 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(){
Ответ 5
Да. Это потому что свойство 'selected' для 'select' DOM node отличается от атрибута 'selected' параметров. jQuery никак не изменяет атрибуты параметров.
Попробуйте это вместо:
$('option', select).get(1).setAttribute('selected', 'selected');
// starting from 0 ^
Если вам действительно интересно, как работает функция val, вы можете изучить
alert($.fn.val)
Ответ 6
Клонирование a <select>
делает не копировать свойство value=
на <option>
s. Таким образом, плагин 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
.
Ответ 7
Упрощение ответа главного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
Ответ 8
Если вам просто нужно значение select, чтобы сериализовать форму или что-то в этом роде, это работает для меня:
$clonedForm.find('theselect').val($origForm.find('theselect').val());
Ответ 9
После 1 часа попыток разных решений, которые не сработали, я создал это простое решение
$clonedItem.find('select option').removeAttr('selected');
$clonedItem.find('select option[value="' + $originaItem.find('select').val() + '"]').attr('selected', 'true');
Ответ 10
@pie6k показать хорошую идею.
Он решил мою проблему. Я немного изменяю его:
$(document).on("change", "select", function(){
var val = $(this).val();
$(this).find("option[value=" + val + "]").attr("selected",true);
});
Ответ 11
$(document).on("change", "select", function(){
original = $("#original");
clone = $(original.clone());
clone.find("select").val(original.find("select").val());
});