web-dev-qa-db-fra.com

Redimensionnement automatique de l'élément SELECT en fonction de la largeur de l'OPTION sélectionnée

J'ai cet élément select avec différents option dedans. Normalement, l'élément select tirera sa largeur du plus grand élément option, mais je veux que l'élément select ait la largeur par défaut de la valeur option qui est plus courte . Lorsque l'utilisateur sélectionne un autre option, l'élément select doit se redimensionner pour que tout le texte soit toujours visible dans l'élément.

$(document).ready(function() {
    $('select').change(function(){
        $(this).width($('select option:selected').width());
    });
});

Problème:

  • Sur Chrome (Canary), il obtient toujours une largeur renvoyée de 0.
  • Sur Firefox, la largeur est ajoutée et n'est pas redimensionnée lorsqu'elle est sélectionnée avec une option plus courte.
  • Safari: même résultat que Chrome.

Démo @ JSFiddle

24
Th3Alchemist

Vous avez raison, il n'y a aucun moyen facile ou intégré d'obtenir la taille d'une option de sélection particulière. Voici un JsFiddle qui fait ce que vous voulez.

Il est compatible avec les dernières versions de Chrome, Firefox, IE, Opera and Safari.

J'ai ajouté une sélection masquée #width_tmp_select pour calculer la largeur du visible sélectionnez #resizing_select que nous voulons redimensionner automatiquement. Nous définissons la sélection masquée pour avoir une seule option, dont le texte est celui de l'option actuellement sélectionnée de la sélection visible. Ensuite, nous utilisons la largeur de la sélection cachée comme largeur de la sélection visible. Notez que l'utilisation d'une plage masquée au lieu d'une sélection masquée fonctionne plutôt bien, mais la largeur sera un peu décalée comme le souligne sami-al-subhi dans le commentaire ci-dessous.

$(document).ready(function() {
  $('#resizing_select').change(function(){
    $("#width_tmp_option").html($('#resizing_select option:selected').text()); 
    $(this).width($("#width_tmp_select").width());  
  });
});
#resizing_select {
  width: 50px;
} 
 
#width_tmp_select{
  display : none;
} 
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>

<select id="resizing_select">
  <option>All</option>
  <option>Longer</option>
  <option>A very very long string...</option>
</select>

<select id="width_tmp_select">
  <option id="width_tmp_option"></option>
</select>
41
kmas

Voici un plugin que je viens d'écrire pour cette question qui crée et détruit dynamiquement une maquette span pour ne pas encombrer votre html. Cela permet de séparer les préoccupations, vous permet de déléguer cette fonctionnalité et permet une réutilisation facile sur plusieurs éléments.

Incluez ce JS n'importe où:

(function($, window){
  var arrowWidth = 30;

  $.fn.resizeselect = function(settings) {  
    return this.each(function() { 

      $(this).change(function(){
        var $this = $(this);

        // create test element
        var text = $this.find("option:selected").text();
        var $test = $("<span>").html(text).css({
            "font-size": $this.css("font-size"), // ensures same size text
            "visibility": "hidden"               // prevents FOUC
        });


        // add to parent, get width, and get out
        $test.appendTo($this.parent());
        var width = $test.width();
        $test.remove();

        // set select width
        $this.width(width + arrowWidth);

        // run on start
      }).change();

    });
  };

  // run by default
  $("select.resizeselect").resizeselect();                       

})(jQuery, window);

Vous pouvez initialiser le plugin de deux manières:

  1. [~ # ~] html [~ # ~] - Ajoutez la classe .resizeselect à n'importe quel élément de sélection:

    <select class="btn btn-select resizeselect">
      <option>All</option>
      <option>Longer</option>
      <option>A very very long string...</option>
    </select>
    
  2. JavaScript - Appelez .resizeselect() sur n'importe quel objet jQuery:

    $("select").resizeselect()
    

Voici un Démo dans jsFiddle

Voici une démo dans les extraits de pile:

(function($, window){
  var arrowWidth = 30;

  $.fn.resizeselect = function(settings) {  
    return this.each(function() { 

      $(this).change(function(){
        var $this = $(this);

        // create test element
        var text = $this.find("option:selected").text();
        var $test = $("<span>").html(text).css({
                "font-size": $this.css("font-size"), // ensures same size text
            "visibility": "hidden"               // prevents FOUC
        });
        
        // add to parent, get width, and get out
        $test.appendTo($this.parent());
        var width = $test.width();
        $test.remove();

        // set select width
        $this.width(width + arrowWidth);

        // run on start
      }).change();

    });
  };

  // run by default
  $("select.resizeselect").resizeselect();                       

})(jQuery, window);
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>

<select class="resizeselect">
  <option>All</option>
  <option>Longer</option>
  <option>A very very long string...</option>
</select>

Mis à jour pour inclure des suggestions de dimensionnement de Garywoo & Eric Warnke

15
KyleMit

Essayez le simple JavaScript suivant et convertissez-le en jQuery :)

<html><head><title>Auto size select</title>

<script>
var resized = false;

function resizeSelect(selected) {
  if (resized) return;
  var sel = document.getElementById('select');
  for (var i=0; i<sel.options.length; i++) {
    sel.options[i].title=sel.options[i].innerHTML;
    if (i!=sel.options.selectedIndex) sel.options[i].innerHTML='';
  }
  resized = true;
  sel.blur();
}

function restoreSelect() {
  if (!resized) return;
  var sel = document.getElementById('select');
  for (var i=0; i<sel.options.length; i++) {
    sel.options[i].innerHTML=sel.options[i].title;
  }  
  resized = false;
}
</script>

</head>
<body onload="resizeSelect(this.selectedItem)">
<select id="select" 
  onchange="resizeSelect(this.selectedItem)"
  onblur="resizeSelect(this.selectedItem)"
  onfocus="restoreSelect()">
<option>text text</option>
<option>text text text text text</option>
<option>text text text </option>
<option>text text text text </option>
<option>text</option>
<option>text text text text text text text text text</option>
<option>text text</option>
</select>
</body></html>

Voici un jsfiddle pour cela: https://jsfiddle.net/sm4dnwuf/1/

Fondamentalement, il supprime temporairement les éléments non sélectionnés lorsqu'il n'est pas mis au point (ce qui le redimensionne à la taille de l'élément sélectionné).

3
Divyesh

Cette solution de travail utilise ici un select auxiliaire temporaire dans lequel l'option sélectionnée dans la sélection principale est clonée, de sorte que l'on peut évaluer la largeur réelle que le select principal devrait avoir.

La bonne chose ici est que vous ajoutez simplement ce code et qu'il s'applique à chaque sélection, donc pas besoin de ids et de noms supplémentaires.

$('select').change(function(){
  var text = $(this).find('option:selected').text()
  var $aux = $('<select/>').append($('<option/>').text(text))
  $(this).after($aux)
  $(this).width($aux.width())
  $aux.remove()
}).change()
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select>
  <option>REALLY LONG TEXT, REALLY LONG TEXT, REALLY LONG TEXT</option>
  <option>ABCDEFGHIJKL</option>
  <option>ABC</option>
</select>

Vous pouvez utiliser une fonction simple:

// Function that helps to get the select element width.
$.fn.getSelectWidth = function() {
  var width = Math.round($(this).wrap('<span></span>').width());
  $(this).unwrap();
  return width;
}

Ensuite, utilisez-le simplement sur votre élément de sélection de formulaire:

$(this).getSelectWidth();
1
Jack

Voici encore une autre solution jQuery simple:

$('#mySelect').change(function(){
    var $selectList = $(this);

    var $selectedOption = $selectList.children('[value="' + this.value + '"]')
        .attr('selected', true);
    var selectedIndex = $selectedOption.index();

    var $nonSelectedOptions = $selectList.children().not($selectedOption)
        .remove()
        .attr('selected', false);

    // Reset and calculate new fixed width having only selected option as a child
    $selectList.width('auto').width($selectList.width());

    // Add options back and put selected option in the right place on the list
    $selectedOption.remove();
    $selectList.append($nonSelectedOptions);
    if (selectedIndex >= $nonSelectedOptions.length) {
         $selectList.append($selectedOption);
    } else {
         $selectList.children().eq(selectedIndex).before($selectedOption);
    }
});
1
Antwerp Danish