2009-04-13 6 views
60

Ich habe es nicht erwartet, aber der folgende Test nicht auf dem Scheck geklont Wert:Clone ist das Klonen nicht wählen Werte

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

Ist das richtig?

Antwort

2

Ja. Dies ist because. Die Eigenschaft 'selected' eines DOM-Knotens unterscheidet sich vom Attribut 'selected' der Optionen. jQuery ändert die Attribute der Optionen in keiner Weise.

Versuchen Sie stattdessen:

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

Wenn Sie wirklich daran interessiert sind, wie die val-Funktion funktioniert, möchten Sie vielleicht

alert($.fn.val) 
+0

Wenn ich die val() auf dem ausgewählten Objekt verwenden, den Test nicht bestehen auch: \t-Test („Klon sollten Werte von ausgewählten behalten“, function() { \t \t var select = $ (“").anhängen ($ ("

59

Nach weiterer Forschung untersuchen, fand ich dieses Ticket in der JQuery Bug Tracker-System, das den Fehler erklärt und eine Arbeit bietet. Offensichtlich ist es zu teuer, die Auswahlwerte zu klonen, damit sie nicht behoben werden.

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

Meine Verwendung der Klon-Methode wurde in einem allgemeinen Verfahren, bei dem alles geklont werden könnte so nicht sicher, dass ich, wann oder ob es eine Auswahl sein auf den Wert einzustellen. So habe ich die folgenden:

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

Sie erklären nicht, warum es "zu teuer" ist. Ich bin überrascht, dass es 8 Jahre später keine bessere Lösung gibt. –

+1

Warum guckst du nicht nur nach Änderungen und fügst 'html'' selected' Attribut bei jeder Änderung hinzu, damit es einfach geklont wird? – pie6k

+0

Bug Ticket Beschwerden (feste URL: https://bugs.jquery.com/ticket/1294) gegen IE, aber es funktioniert nirgendwo. Testen Sie Ihren Browser mit dieser Geige: https://jsfiddle.net/ygmL0k8m/4/ – hejdav

8

Hergestellt ein Plugin aus chief7 Antwort:

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

Nur kurz getestet, aber es scheint zu funktionieren.

2

ein <select> Klonen macht nicht die value= Eigenschaft auf <option> s kopieren. Also funktioniert Marks Plugin nicht in allen Fällen.

zu beheben, tun dies vor die <select> Werte Klonen:

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

Eine andere Art und Weise zu klonen, die, 1.6.1 in jQuery + ...

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

// use this: 
$clonedSelects.eq(i).prop('selectedIndex', $(this).prop('selectedIndex')); 
ausgewählt ist <select> Option

Letzteres ermöglicht es Ihnen, die <option> Werte nach Einstellung der einzustellen.

22

Hier ist eine feste Version der Klon-Methode für 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 Das ist ein tolles Plugin. Bitte führen Sie dieses Projekt weiter aus. – Houman

+1

Das funktioniert super! Warum kann jQuery es nicht tun, Devs mit Clone verstehe es teuer ... aber wir MÜSSEN es auf irgendeine Weise tun .. jeeez ... so viel Zeit damit verschwendet, das zu debuggen. Danke, dieser Fix funktioniert super! + Bier – ppumkin

2

Vereinfachung der Antwort der chief7:

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

Wieder ist hier das jQuery-Ticket: http://bugs.jquery.com/ticket/1294

0

Wenn Sie nur n den Wert der ausgewählten eed, das Formular oder so etwas wie es serialisiert werden, das für mich funktioniert:

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

Nach 1 Stunde verschiedene Lösungen zu versuchen, die nicht funktioniert, ich habe diese einfache Lösung erstellen

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

Mein Ansatz ist ein bisschen anders.

Stattdessen wählt während des Klonens zu modifizieren, gucke ich nur jeden select auf Seite für change Ereignis, und dann, wenn der Wert geändert wird, füge ich hinzu benötigt selected Attribut ausgewählt <option> so <option selected="selected"> wird es. Da die Auswahl jetzt in <option> Markup markiert ist, wird es übergeben, wenn Sie .clone() it.

Der einzige Code, den Sie benötigen:

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

Und jetzt können Sie, wie Sie wollen kopieren auswählen und es wird es Wert zu kopiert haben.

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

Ich denke, diese Lösung weniger ist benutzerdefinierte so brauchen Sie sich keine Sorgen machen, wenn Ihr Code brechen, wenn Sie etwas später ändern werde.

Wenn Sie es nicht wollen alle auf Seite wählen angewendet werden, können Sie Wähler in der ersten Zeile wie ändern:

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

Ich dachte, dass diese Herangehensweise ziemlich clever war, also habe ich sie fast benutzt - aber irgendwann habe ich gemerkt, dass sie dem Geist des Attributs "selected" widerspricht, das sich eigentlich nicht ändern sollte, da es die Initiale darstellt. Wert für das