Sao chép không nhân bản các giá trị đã chọn


77

Tôi không mong đợi điều đó nhưng thử nghiệm sau không thành công khi kiểm tra giá trị nhân bản:

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

Thê nay đung không?

Câu trả lời:


76

Sau khi nghiên cứu thêm, tôi tìm thấy phiếu này trong hệ thống theo dõi lỗi JQuery, giải thích lỗi và cung cấp cách khắc phục. Rõ ràng, quá đắt để sao chép các giá trị đã chọn để chúng không sửa chữa nó.

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

Việc sử dụng phương pháp sao chép của tôi là trong một phương pháp chung mà mọi thứ có thể được sao chép vì vậy tôi không chắc khi nào hoặc liệu sẽ có một lựa chọn để đặt giá trị. Vì vậy, tôi đã thêm những điều sau:

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

13
Họ không giải thích tại sao nó "quá đắt". Tôi ngạc nhiên là không có giải pháp nào tốt hơn 8 năm sau.
Tyler Collier

1
Tại sao không chỉ xem các lựa chọn cho các thay đổi và thêm html selectedthuộc tính vào bất kỳ thay đổi nào để nó được nhân bản dễ dàng?
Adam Pietrasiak,

Khiếu nại về lỗi vé (URL đã sửa: bug.jquery.com/ticket/1294 ) đối với IE, nhưng nó không hoạt động ở đâu cả. Kiểm tra browesr của bạn bằng cách fiddle này: jsfiddle.net/ygmL0k8m/4
hejdav

Bản sửa lỗi này không hoạt động đối với tôi. Câu trả lời dưới đây (Novalis ') đã hoạt động.
aromadonmr 27/07/17

36

Đây là phiên bản cố định của phương thức sao chép cho 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 Đó là một plugin tuyệt vời. Hãy tiếp tục duy trì dự án này.
Houman 20/12/12

2
Điều này hoạt động tuyệt vời! Tại sao jQuery không thể làm điều đó, các nhà phát triển đang sử dụng Clone hiểu rằng nó đắt đỏ ... nhưng chúng tôi CẦN làm theo bất kỳ cách nào .. jeeez ... quá lãng phí thời gian để gỡ lỗi này. Cảm ơn, bản sửa lỗi này hoạt động tốt! + bia
Piotr Kula

ai đó có thể giải thích làm thế nào để áp dụng điều này? ví dụ trong trường hợp $('.inputPrefixListIx:first').clone().insertAfter('.inputPrefixListIx:last');nó sẽ trông như thế nào khi xem xétjQuery.fn.clone ?
nskalis

không hoạt động với nhiều lựa chọn. Nó chỉ chọn tùy chọn đầu tiên (((
Сергей Сергеев

8

Tạo một plugin từ câu trả lời của 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);

Chỉ thử nghiệm nó một thời gian ngắn, nhưng nó dường như hoạt động.


6

Cách tiếp cận của tôi hơi khác một chút.

Thay vì sửa đổi các lựa chọn trong quá trình sao chép, tôi chỉ xem mọi sự kiện selecttrên trang changevà sau đó, nếu giá trị được thay đổi, tôi thêm selectedthuộc tính cần thiết vào đã chọn <option>để nó trở thành <option selected="selected">. Vì lựa chọn hiện đã được đánh dấu trong <option>đánh dấu của, nó sẽ được chuyển khi bạn.clone() .

Mã duy nhất bạn cần:

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

Và bây giờ, bạn có thể sao chép lựa chọn theo bất kỳ cách nào bạn muốn và nó cũng sẽ được sao chép giá trị của nó.

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

Tôi nghĩ rằng giải pháp này ít tùy chỉnh hơn nên bạn không cần phải lo lắng nếu mã của bạn sẽ bị hỏng nếu bạn sửa đổi điều gì đó sau đó.

Nếu bạn không muốn nó được áp dụng cho mọi lựa chọn trên trang, bạn có thể thay đổi bộ chọn trên dòng đầu tiên như:

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

Tôi nghĩ rằng cách tiếp cận này khá thông minh nên tôi đã gần như sử dụng nó - tuy nhiên, cuối cùng tôi nhận ra rằng nó đi ngược lại tinh thần của thuộc tính "đã chọn", thuộc tính không thực sự được cho là thay đổi vì nó đại diện cho giá trị ban đầu (mặc định) cho phần tử <select>. Nguồn: api.jquery.com/prop
etipton

Nhược điểm của việc thay đổi nó là gì? I E. thay đổi initial selection?
Adam Pietrasiak

Thực tế , tôi không thể nghĩ ra bất kỳ nhược điểm thực sự nào của TBH. Chỉ chỉ ra rằng về mặt kỹ thuật, nó đi ngược lại với thông số kỹ thuật của W3C. Nhưng không phải là một cách chính (vì vậy vẫn là một giải pháp tốt).
etipton

4

Đơn giản hóa câu trả lời của Chief7:

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

Một lần nữa, đây là vé jQuery: http://bugs.jquery.com/ticket/1294


2

Đúng. Điều này là do thuộc tính 'đã chọn' của nút DOM 'chọn' khác với thuộc tính 'đã chọn' của các tùy chọn. jQuery không sửa đổi các thuộc tính của tùy chọn theo bất kỳ cách nào.

Hãy thử cái này thay thế:

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

Nếu bạn thực sự quan tâm đến cách hoạt động của hàm val, bạn có thể muốn kiểm tra

alert($.fn.val)

Nếu tôi sử dụng val () trên đối tượng được chọn thì quá trình kiểm tra cũng không thành công: test ("clone nên giữ lại các giá trị của select", function () {var select = $ ("<select>") .append ($ ("< option> "). val (" 1 ")). append ($ (" <option> ") .val (" 2 ")); $ (select) .val (" 2 "); equals ($ (select) .val (), "2", "mong đợi 2"); var cl
Chief7

Điều đó khá kỳ lạ, vì nó hoạt động với tôi trên IE 6/7, Firefox 3 và Opera 9. Có thể có gì đó sai với chức năng 'bằng' của bạn? alert (eval ('select = $ ("<select>") .append ($ ("<option>") .val ("1")). append ($ ("<option>") .val ("2 ")); $ (chọn) .val (" 2 "); $ (chọn) .val () '));
user123444555621

2

Nhân bản một <select>không không sao chép các value=tài sản trên<option> s. Vì vậy, plugin của Mark không hoạt động trong mọi trường hợp.

Để khắc phục, hãy làm điều này trước khi sao chép các <select>giá trị:

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

Một cách khác để sao chép <select>tùy chọn được chọn, trong jQuery 1.6.1 + ...

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

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

Cái sau cho phép bạn đặt các <option>giá trị sau khi đặt selectedIndex.


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

});

0

Nếu bạn chỉ cần giá trị của lựa chọn, để tuần tự hóa biểu mẫu hoặc thứ gì đó tương tự, điều này phù hợp với tôi:

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

0

Sau 1 giờ thử các giải pháp khác nhau mà không hiệu quả, tôi đã tạo ra giải pháp đơn giản này

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

0

@ pie6k cho thấy một ý kiến ​​hay.

Nó đã giải quyết vấn đề của tôi. Tôi thay đổi nó một chút nhỏ:

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

0

chỉ báo cáo lại. Vì một số lý do thần thánh không rõ và mặc dù đây là điều đầu tiên tôi thử nghiệm và tôi chưa thay đổi mã của mình, bây giờ

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

cách tiếp cận đang hoạt động. Tôi không biết tại sao hoặc liệu nó sẽ ngừng hoạt động trở lại ngay sau khi tôi thay đổi thứ gì đó, nhưng tôi sẽ tiếp tục với điều này ngay bây giờ. Cảm ơn mọi người đã giúp đỡ!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.