Comment masquer une <option> dans un menu <select> avec CSS?

103

J'ai réalisé que Chrome, semble-t-il, ne me permettra pas de me cacher <option>dans un fichier <select>. Firefox le fera.

J'ai besoin de masquer les <option>s qui correspondent à un critère de recherche. Dans les outils Web Chrome, je peux voir qu'ils sont correctement définis display: none;par mon JavaScript, mais une fois que le <select>menu est cliqué, ils sont affichés.

Comment puis-je faire en sorte que ceux <option>qui correspondent à mes critères de recherche ne s'affichent PAS lorsque l'utilisateur clique sur le menu? Merci!

Jesse Atkinson
la source
4
Au lieu de se cacher et de s'afficher lors d'une recherche. Essayez de renseigner la sélection en fonction de la recherche
Henesnarfel
1
Je suis d'accord avec Henesnarfel. Si vous effectuez déjà une recherche ou une sorte de requête, vous devriez être en mesure de renseigner uniquement celles que vous souhaitez.
Michael Stramel
1
cela fonctionne très bien pour moi dans Chrome 16.0.912.77 m. Est-ce que je comprends mal le problème?
mgibsonbr
3
@mgibsonbr Cela ne fonctionne pas avec plusieurs navigateurs.
Jasper
3
@Henesnarfel Il peut y avoir de bonnes raisons de cacher des options. Par exemple, j'avais une page avec une liste de sélection et des liens pour masquer ou afficher les éléments marqués comme inactifs. Aucune raison de conserver plusieurs listes ou d'interroger le serveur pour une nouvelle liste chaque fois que l'utilisateur modifie cette option.
Ryan P

Réponses:

69

Vous devez implémenter deux méthodes pour se cacher. display: nonefonctionne pour FF, mais pas Chrome ou IE. La deuxième méthode consiste donc à envelopper le <option>dans un <span>avec display: none. FF ne le fera pas (HTML techniquement non valide, selon la spécification) mais Chrome et IE le feront et masqueront l'option.

EDIT: Oh ouais, j'ai déjà implémenté cela dans jQuery:

jQuery.fn.toggleOption = function( show ) {
    jQuery( this ).toggle( show );
    if( show ) {
        if( jQuery( this ).parent( 'span.toggleOption' ).length )
            jQuery( this ).unwrap( );
    } else {
        if( jQuery( this ).parent( 'span.toggleOption' ).length == 0 )
            jQuery( this ).wrap( '<span class="toggleOption" style="display: none;" />' );
    }
};

EDIT 2: Voici comment vous utiliseriez cette fonction:

jQuery(selector).toggleOption(true); // show option
jQuery(selector).toggleOption(false); // hide option

EDIT 3: Ajout d'une vérification supplémentaire suggérée par @ user1521986

Ryan P
la source
1
Cette méthode folle est la seule qui fonctionnait complètement entre les navigateurs et n'impliquait pas de créer un hack de boîte de sélection faux-caché.
Jesse Atkinson
15
Soyez prudent avec cela. Cela semble fonctionner très bien au début, mais quelque part le long de la ligne, il s'arrête. Voici une petite démo: jsfiddle.net/Yb6sk/9
Bill Criswell
17
Bien que cette solution masque l'élément, toute tentative de lecture de la valeur de <select>(en utilisant jQuery .val()) sera renvoyée null. Je viens de tester cela dans Chrome 29, alors les Googleurs méfiez-vous!
Mark le
10
Piratage intéressant, mais je recommanderais d'éviter le "HTML techniquement invalide" si possible.
Luke
3
Certes, tous les navigateurs ont des implémentations différentes. Mais l'une des raisons pour lesquelles les navigateurs ne peuvent pas appliquer strictement les spécifications standard est qu'il y a trop de code en direct qui ne respecte pas les spécifications. IMO: S'il n'y a pas d'autres solutions, utilisez certainement un hack. Mais si vous pouvez suivre les spécifications et résoudre votre problème, pourquoi pas vous? Cela aide votre code à bien jouer avec les autres et aide à renforcer les spécifications.
Luke
82

Pour HTML5, vous pouvez utiliser l'attribut «masqué».

<option hidden>Hidden option</option>

Il n'est pas pris en charge par IE <11. Mais si vous n'avez besoin que de masquer quelques éléments, il serait peut-être préférable de simplement définir l'attribut masqué en combinaison avec désactivé par rapport à l'ajout / suppression d'éléments ou à des constructions sémantiquement incorrectes.

<select>  
  <option>Option1</option>
  <option>Option2</option>
  <option hidden>Hidden Option</option>
</select>

Référence .

Lukas Jelinek
la source
4
IE 11 prend en charge cela.
Iván Pérez
7
Telle est la réponse moderne. Idéalement, nous définissons également ceci pour disabledque les navigateurs qui ne prennent pas en charge l' attribut global HTML5hidden aient une indication visuelle pour l'utilisateur.
cloudworks
1
Comment utilisez-vous cette technique avec CSS?
GetFree
7
Ne fonctionne pas dans Safari, Edge ni IE. Le bogue pour Safari a 10 ans, veuillez aider en mettant à jour les correctifs existants. Impossible de trouver un bogue dans le suivi des problèmes Edge.
Indolering
7
Une solution de contournement pour cela consiste à utiliser <option hidden disabled>, de sorte qu'il se cache dans tous les bons navigateurs et le désactive sur les autres.
Ramon Balthazar
37

Je vous suggère de ne pas utiliser les solutions qui utilisent un <span>wrapper car ce n'est pas du HTML valide, ce qui pourrait causer des problèmes plus tard. Je pense que la solution préférée est de supprimer toutes les options que vous souhaitez masquer et de les restaurer si nécessaire. En utilisant jQuery, vous n'aurez besoin que de ces 3 fonctions:

La première fonction enregistrera le contenu original de la sélection . Pour plus de sécurité, vous pouvez appeler cette fonction lorsque vous chargez la page.

function setOriginalSelect ($select) {
    if ($select.data("originalHTML") == undefined) {
        $select.data("originalHTML", $select.html());
    } // If it's already there, don't re-set it
}

Cette fonction suivante appelle la fonction ci-dessus pour s'assurer que le contenu d'origine a été enregistré, puis supprime simplement les options du DOM.

function removeOptions ($select, $options) {
    setOriginalSelect($select);
    $options.remove();
 }

La dernière fonction peut être utilisée chaque fois que vous souhaitez "réinitialiser" toutes les options d'origine.

function restoreOptions ($select) {
    var ogHTML = $select.data("originalHTML");
    if (ogHTML != undefined) {
        $select.html(ogHTML);
    }
}

Notez que toutes ces fonctions s'attendent à ce que vous passiez des éléments jQuery. Par exemple:

// in your search function...
var $s = $('select.someClass');
var $optionsThatDontMatchYourSearch= $s.find('options.someOtherClass');
restoreOptions($s); // Make sure you're working with a full deck
removeOptions($s, $optionsThatDontMatchYourSearch); // remove options not needed

Voici un exemple de travail: http://jsfiddle.net/9CYjy/23/

Luke
la source
3
Fiable et pas un hack. Très bonne réponse!
Jeremy Cook
1
@DanBeaulieu Il y avait une fonction nommée incorrectement dans le jsfiddle précédent. J'ai corrigé et mis à jour le lien ci-dessus. Merci d'avoir attrapé ça.
Luke
Oui, celui-ci était aussi mon choix. En fait, j'ai réussi à golf le code un peu plus petit, en prenant d'abord la valeur des données dans une variable, si elle n'est pas définie, elle enregistrera les options, sinon elle restaurera les options. Mon besoin était spécifique pour tel.
diynevala
1
J'ai dû ajouter var value=$select.val(); $select.html(ogHTML); $select.val(value);pour garder la valeur sélectionnée sélectionnée même après la restauration.
diynevala
Le cycle de sélection des options pour les supprimer et les supprimer n'a fonctionné qu'une seule fois. Après cela, options.remove () n'a eu aucun effet pour moi. Une fois que j'ai déplacé le restoreOptions ($ s) appeler quelques lignes pour que je travaille toujours avec un objet Select complet et frais, cela a fonctionné.
Newclique
18

La réponse de Ryan P devrait être changée en:

    jQuery.fn.toggleOption = function (show) {
        $(this).toggle(show);
        if (show) {
            if ($(this).parent('span.toggleOption').length)
                $(this).unwrap();
        } else {
            **if ($(this).parent('span.toggleOption').length==0)**
                $(this).wrap('<span class="toggleOption" style="display: none;" />');
        }
    };

Sinon, il est enveloppé dans trop de balises

JeffT
la source
5
Notez que selon les spécifications HTML ( w3.org/TR/html5/forms.html#the-select-element ), a <select>ne doit contenir que des éléments de support de script <option>or <optgroup>ou. Vous devez donc éviter d'utiliser des <span>wrappers non valides .
Luke
9

La fonction toggleOption n'est pas parfaite et a introduit de vilains bugs dans mon application. jQuery sera confondu avec .val () et .arraySerialize () Essayez de sélectionner les options 4 et 5 pour voir ce que je veux dire:

<select id="t">
<option value="v1">options 1</option>
<option value="v2">options 2</option>
<option value="v3" id="o3">options 3</option>
<option value="v4">options 4</option>
<option value="v5">options 5</option>
</select>
<script>
jQuery.fn.toggleOption = function( show ) {
    jQuery( this ).toggle( show );
    if( show ) {
        if( jQuery( this ).parent( 'span.toggleOption' ).length )
            jQuery( this ).unwrap( );
    } else {
        jQuery( this ).wrap( '<span class="toggleOption" style="display: none;" />' );
    }
};

$("#o3").toggleOption(false); 
$("#t").change(function(e) {
    if($(this).val() != this.value) {
    console.log("Error values not equal", this.value, $(this).val());
    }
});
</script>
Batiste Bieler
la source
8

Les entrées sélectionnées sont délicates de cette manière. Que diriez-vous de le désactiver à la place, cela fonctionnera entre les navigateurs:

$('select').children(':nth-child(even)').prop('disabled', true);

Cela désactivera tous les autres <option>éléments, mais vous pouvez sélectionner celui que vous voulez.

Voici une démo: http://jsfiddle.net/jYWrH/

Remarque: si vous souhaitez supprimer la propriété disabled d'un élément, vous pouvez utiliser .removeProp('disabled').

Mettre à jour

Vous pouvez enregistrer les <option>éléments que vous souhaitez masquer dans l'élément de sélection masqué:

$('#visible').on('change', function () {
    $(this).children().eq(this.selectedIndex).appendTo('#hidden');
});

Vous pouvez ensuite rajouter les <option>éléments à l'élément de sélection d'origine:

$('#hidden').children().appendTo('#visible');

Dans ces deux exemples, on s'attend à ce que l'élément de sélection visible ait l'id de visibleet que l'élément de sélection masqué ait l'id de hidden.

Voici une démo: http://jsfiddle.net/jYWrH/1/

Notez que .on()c'est nouveau dans jQuery 1.7 et que l'utilisation de cette réponse est la même que .bind(): http://api.jquery.com/on

Jaspe
la source
7

Réponse simple: vous ne pouvez pas. Les éléments de formulaire ont des capacités de style très limitées.

La meilleure alternative serait de définir disabled=truel'option (et peut-être une couleur grise, puisque seul IE le fait automatiquement), ce qui rendra l'option non cliquable.

Sinon, si vous le pouvez, supprimez complètement l' optionélément.

Niet the Dark Absol
la source
6
// Simplest way

var originalContent = $('select').html();

$('select').change(function() {
    $('select').html(originalContent); //Restore Original Content
    $('select option[myfilter=1]').remove(); // Filter my options
});
René Berwanger
la source
4

Puisque vous utilisez déjà JS, vous pouvez créer un élément SELECT masqué sur la page, et pour chaque élément que vous essayez de masquer dans cette liste, déplacez-le vers la liste masquée. De cette façon, ils peuvent être facilement restaurés.

Je ne connais pas de manière désinvolte de le faire en CSS pur ... J'aurais pensé que l'affichage: aucune astuce n'aurait fonctionné.

Derreck Dean
la source
2

!!! AVERTISSEMENT !!!

Remplacez le deuxième "IF" par "WHILE" ou ne fonctionne pas!

jQuery.fn.toggleOption = function( show ) {
    jQuery( this ).toggle( show );
    if( show ) {
        while( jQuery( this ).parent( 'span.toggleOption' ).length )
            jQuery( this ).unwrap( );
    } else {
        jQuery( this ).wrap( '<span class="toggleOption" style="display: none;" />' );
    }
};
Arraxas
la source
2

Vous devez les supprimer de l' <select>utilisation de JavaScript. C'est le seul moyen garanti de les faire disparaître.

Jordan
la source
1
En utilisant jQuery, cela peut être fait avec remove:$('options').remove();
Luke
2

celui-ci semble fonctionner pour moi en chrome

$("#selectid span option").unwrap();
$("#selectid option:not([filterattr=filtervalue])").wrap('<span/>');
exilé
la source
1
Veuillez ajouter un format de code à votre code, soit en indentant avec 4 espaces, soit en enveloppant votre code avec `.
Banana
1
ce code est génial! cela fonctionne sur les derniers Chrome, Firefox et IE 11, c'est assez bien pour moi :)
Sijav
1
avant mon dernier commentaire, cette chose fonctionne aussi sur IE 7! donc ff 3.5, c'est ce que j'ai trouvé en dernier lieu, en quelque sorte sur IE et chrome conservent la valeur qui a été sélectionnée avant que les options ne soient cachées et si une autre valeur n'est pas définie après le retour du navigateur d'options, le navigateur définira l'option sélectionné comme avant!
Sijav
0

Tard dans le match, mais la plupart semblent assez compliqués.

Voici comment je l'ai fait:

var originalSelect = $('#select-2').html();

// filter select-2 on select-1 change
$('#select-1').change(function (e) {

    var selected = $(this).val();

    // reset select ready for filtering
    $('#select-2').html(originalCourseSelect);

    if (selected) {
        // filter
        $('#select-2 option').not('.t' + selected).remove();
    }

});

balisage de select-1:

<select id='select-1'>
<option value=''>Please select</option>
<option value='1'>One</option>
<option value='2'>Two</option>
</select>

balisage de select-2:

<select id='select-2'>
<option class='t1'>One</option>
<option class='t2'>Two</option>
<option>Always visible</option>
</select>
RichardAtHome
la source