83 votes

Le Clone n'est pas le clonage de sélectionner les valeurs

Je ne m'attendais pas, mais le test suivant échoue sur la cloné valeur de vérifier:

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

Est-ce exact?

82voto

chief7 Points 2422

Après de nouvelles recherches, j'ai trouvé ce billet dans le JQuery bug tracker système qui explique le bug, et fournit un travail autour de. Apparemment, c'est trop cher pour cloner le sélectionner des valeurs de sorte qu'ils ne le répare pas.

http://dev.jquery.com/ticket/1294

Mon utilisation de la méthode clone était dans une méthode générique où tout pourrait être cloné donc je ne sais pas quand ou si il y aura une sélection pour définir la valeur sur. J'ai donc ajouté ce qui suit:

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

39voto

Novalis Points 101

Voici une version corrigée de la méthode clone de 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);

10voto

Mark Points 49079

Fait un plugin de chief7 de réponse:

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

Seulement testé brièvement, mais il semble fonctionner.

2voto

Pumbaa80 Points 27066

Oui. C'est parce que le "selected" la propriété d'un 'select' nœud DOM diffère de l'attribut 'selected' des options. jQuery ne permet pas de modifier les options des attributs d'une quelconque façon.

Essayez plutôt ceci:

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

Si vous êtes vraiment intéressé par la façon dont la fonction val de travaux, vous souhaiterez peut-être examiner

alert($.fn.val)

2voto

jamesvl Points 411

Le clonage d'un <select> ne pas copier l' value= bien sur <option>s. Donc la Marque du plugin ne fonctionne pas dans tous les cas.

Pour corriger, le faire avant le clonage de l' <select> valeurs:

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

Une autre façon de clone qui <select> option est sélectionnée, jQuery 1.6.1+...

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

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

Ce dernier permet de définir l' <option> valeurs après le réglage de l' selectedIndex.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X