2009-04-13 8 views
60

que no esperaba, pero la siguiente prueba falla en la comprobación de valor clonado:Clon no es la clonación seleccione valores

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

¿Es esto así?

Respuesta

2

Sí. Esto es because La propiedad 'seleccionada' de un nodo DOM 'seleccionar' difiere del atributo 'seleccionado' de las opciones. jQuery no modifica los atributos de las opciones de ninguna manera.

Tal vez puedas probar:

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

Si usted está realmente interesado en cómo funciona la función val, es posible que desee examinar

alert($.fn.val) 
+0

Si utilizo el val() en el objeto seleccione la prueba falla, así: \t de prueba ("clon debe mantener los valores de selecto", function() { \t \t var seleccionar = $ (" ").append ($ ("

59

Después de más investigación me encontré con este billete en el jQuery sistema de seguimiento de fallos que explica el error y proporciona una solución alternativa. Aparentemente, es demasiado costoso clonar los valores de selección para que no lo arreglen.

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

Mi uso del método clon fue en un método genérico, donde podría ser clonado nada, así que no estoy seguro de cuándo o si habrá una selección para establecer el valor de. Por lo que añade lo siguiente:

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

No explican por qué es "demasiado caro". Me sorprende que no haya una mejor solución 8 años después. –

+1

¿Por qué no solo mira selecciona los cambios y agrega el atributo 'html'' selected' en cualquier cambio para que se pueda clonar fácilmente? – pie6k

+0

Quejas de errores en los tickets (URL fija: https://bugs.jquery.com/ticket/1294) en contra de IE, pero no funciona en ninguna parte. Pruebe su browesr con este violín: https://jsfiddle.net/ygmL0k8m/4/ – hejdav

8

hicimos un complemento de la respuesta de 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); 

Sólo probado brevemente, pero parece que funciona.

2

La clonación de un <select> hace no copiar la propiedad value= en <option> s. Entonces, el complemento de Mark no funciona en todos los casos.

Para fijar, antes de hacer esto clonación de los valores: <select>

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

Una forma diferente para clonar el cual <select> opción está seleccionada, en jQuery 1.6.1 + ...

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

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

Este último le permite establecer los valores <option>después de configurando el selectedIndex.

22

Aquí hay una versión fija del método clone para 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 Eso es un plugin impresionante. Por favor, continúa manteniendo este proyecto. – Houman

+1

¡Esto funciona genial! ¿Por qué no puede jQuery hacerlo, el uso de Dev para clon es caro ... pero NECESITAMOS hacerlo de cualquier manera ... jeeez ... tanto tiempo perdido tratando de depurar esto. Gracias, esta solución funciona genial! + beer – ppumkin

2

Simplificación de la respuesta de chief7:

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

Una vez más, aquí es el billete de jQuery: http://bugs.jquery.com/ticket/1294

0

Si solo n EED el valor de la selección, para serializar el formulario o algo por el estilo, esto funciona para mí:

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

Después de 1 hora de tratar diferentes soluciones que no funcionó, me he creado esta solución sencilla

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

Mi enfoque es un poco diferente.

En lugar de modificar selecciona durante la clonación, sólo estoy observando cada select en la página de change evento, y luego, si se cambia el valor añado necesaria selected atributo seleccionado a <option> manera que se convierta <option selected="selected">. Como la selección ahora está marcada en el marcado <option>, se aprobará cuando lo haga .clone().

El único código que necesita:

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

Y ahora, puede copiar seleccionar la forma que desee y va a tener su valor copiado también.

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

creo que esta solución es menos personalizada por lo que no tiene que preocuparse si su código se romperá si se le modifique algo más tarde.

Si no desea que se aplica a todos los seleccione en la página, puede cambiar el selector en la primera línea como:

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

Pensé que este enfoque era bastante ingenioso, así que casi lo utilicé; sin embargo, finalmente me di cuenta de que va en contra del espíritu del atributo "seleccionado", que no se supone que cambie, ya que representa el valor inicial (predeterminado) valor para el elemento