Como esconder uma <option> em um menu <select> com CSS?

103

Percebi que o Chrome, ao que parece, não permite que eu me esconda <option>em um <select>. O Firefox vai.

Preciso ocultar os <option>s que correspondem aos critérios de pesquisa. Nas ferramentas da web do Chrome, posso ver que elas estão sendo definidas corretamente display: none;pelo meu JavaScript, mas uma vez que o <select>menu é clicado, elas são exibidas.

Como posso fazer com que esses <option>s que correspondem aos meus critérios de pesquisa NÃO sejam exibidos quando o menu for clicado? Obrigado!

Jesse Atkinson
fonte
4
Em vez de se esconder e mostrar em uma pesquisa. Tente preencher o select de acordo com a pesquisa
Henesnarfel
1
Eu concordo com Henesnarfel. Se você já está fazendo uma pesquisa ou algum tipo de consulta, deve poder preencher apenas os que deseja.
Michael Stramel
1
isso funciona bem para mim no Chrome 16.0.912.77 m. Estou entendendo mal o problema?
mgibsonbr de
3
@mgibsonbr Não funciona em vários navegadores.
Jasper
3
@Henesnarfel Pode haver boas razões para ocultar opções. Por exemplo, eu tinha uma página com uma caixa de listagem selecionada e links para ocultar ou mostrar itens marcados como inativos. Não há razão para manter várias listas ou consultar o servidor por uma nova lista sempre que o usuário alterar essa opção.
Ryan P de

Respostas:

69

Você deve implementar dois métodos de ocultação. display: nonefunciona para FF, mas não para Chrome ou IE. Portanto, o segundo método é envolver o <option>em a <span>com display: none. O FF não fará isso (HTML tecnicamente inválido, de acordo com as especificações), mas o Chrome e o IE farão e ocultarão a opção.

EDIT: Ah sim, já implementei isso no 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: Veja como você usaria esta função:

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

EDIT 3: Adicionada verificação extra sugerida por @ user1521986

Ryan P
fonte
1
Este método maluco é o único que realmente funcionou completamente em vários navegadores e não envolveu a criação de uma caixa de seleção falsa oculta.
Jesse Atkinson
15
Cuidado com isso. Parece funcionar muito bem no início, mas em algum ponto ao longo da linha ele pára. Aqui está uma pequena demonstração: jsfiddle.net/Yb6sk/9
Bill Criswell
17
Embora esta solução oculte o elemento, qualquer tentativa de ler o valor de <select>(usando jQuery .val()) retornará null. Acabei de testar isso no Chrome 29, portanto, os Googlers, cuidado!
Marcos
10
Hack interessante, mas eu recomendaria evitar "HTML tecnicamente inválido" se possível.
Luke
3
É verdade que todos os navegadores têm implementações diferentes. Mas um motivo pelo qual os navegadores não podem implementar estritamente as especificações padrão é porque há muito código ativo por aí que não segue as especificações. IMO: Se não houver outras soluções, use um hack. Mas se você pode seguir as especificações e resolver seu problema, por que não o faria? Isso ajuda seu código a funcionar bem com os outros e ajuda a fortalecer as especificações.
Lucas
82

Para HTML5, você pode usar o atributo 'oculto'.

<option hidden>Hidden option</option>

É não suportado pelo IE <11. Mas se você só precisa de esconder alguns elementos, talvez seria melhor apenas para definir o atributo oculto em combinação com deficientes em comparação a adição / remoção de elementos ou não fazer semanticamente construções corretas.

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

Referência .

Lukas Jelinek
fonte
4
O IE 11 oferece suporte para isso.
Iván Pérez
7
Esta é a resposta moderna. Idealmente, também estamos definindo isso para disabledque os navegadores que não suportam o atributo global HTML5hidden tenham alguma indicação visual para o usuário.
cloudworks de
1
Como você usa essa técnica com CSS?
GetFree
7
Não funciona no Safari, Edge ou IE. Bug para Safari tem 10 anos, por favor ajude atualizando os patches existentes. Não é possível encontrar bug no rastreador de problemas do Edge.
Indolente de
7
Uma solução alternativa para isso é usar <option hidden disabled>, portanto, oculta em todos os bons navegadores e desativa nos outros.
Ramon Balthazar
37

Eu sugeriria que você não use as soluções que usam um <span>invólucro porque não é um HTML válido, o que pode causar problemas no futuro. Acho que a solução preferida é realmente remover todas as opções que você deseja ocultar e restaurá-las conforme necessário. Usando jQuery, você só precisará dessas 3 funções:

A primeira função salvará o conteúdo original da seleção . Por segurança, convém chamar essa função ao carregar a página.

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

A próxima função chama a função acima para garantir que o conteúdo original foi salvo e, em seguida, simplesmente remove as opções do DOM.

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

A última função pode ser usada sempre que você quiser "redefinir" para todas as opções originais.

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

Observe que todas essas funções esperam que você esteja passando elementos jQuery. Por exemplo:

// 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

Aqui está um exemplo prático : http://jsfiddle.net/9CYjy/23/

Lucas
fonte
3
Confiável e não um hack. Ótima resposta!
Jeremy Cook de
1
@DanBeaulieu Havia uma função nomeada incorretamente no jsfiddle anterior. Consertei e atualizei o link acima. Obrigado por pegar isso.
Lucas
Sim, esta também foi minha escolha. Na verdade, consegui reduzir o código um pouco, primeiro colocando o valor dos dados em uma variável, se indefinido, ele salvará as opções, caso contrário, restaurará as opções. Minha necessidade era específica para tal.
diynevala
1
Tive que adicionar var value=$select.val(); $select.html(ogHTML); $select.val(value);para manter o valor selecionado selecionado mesmo após a restauração.
diynevala
O ciclo de seleção das opções para remover e removê-las funcionou apenas uma vez. Depois disso, options.remove () não teve nenhum efeito para mim. Depois que movi restoreOptions ($ s), chamei algumas linhas para que eu estivesse sempre trabalhando com um objeto Select completo e novo, funcionou.
Newclique
18

A resposta de Ryan P deve ser alterada para:

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

Caso contrário, ele fica embrulhado em muitas tags

JeffT
fonte
5
Observe que, de acordo com as especificações HTML ( w3.org/TR/html5/forms.html#the-select-element ), a <select>deve conter apenas <option>ou <optgroup>ou elementos de suporte a script. Portanto, você deve evitar o uso de <span>wrappers inválidos .
Lucas
9

A função toggleOption não é perfeita e introduziu bugs desagradáveis ​​em meu aplicativo. jQuery vai se confundir com .val () e .arraySerialize () Tente selecionar as opções 4 e 5 para ver o que quero dizer:

<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
fonte
8

Selecionar entradas são complicadas dessa forma. Que tal desativá-lo, isso funcionará em todos os navegadores:

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

Isso desativará todos os outros <option>elementos, mas você pode selecionar qualquer um que desejar.

Aqui está uma demonstração: http://jsfiddle.net/jYWrH/

Nota: Se você deseja remover a propriedade disabled de um elemento, você pode usar .removeProp('disabled').

Atualizar

Você pode salvar os <option>elementos que deseja ocultar no elemento de seleção oculto:

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

Você pode então adicionar os <option>elementos de volta ao elemento de seleção original:

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

Nestes dois exemplos, espera-se que o elemento select visível tenha o id de visiblee o elemento select oculto tenha o id hidden.

Aqui está uma demonstração: http://jsfiddle.net/jYWrH/1/

Observe que .on()é novo no jQuery 1.7 e o uso para esta resposta é o mesmo que .bind(): http://api.jquery.com/on

Jaspe
fonte
7

Resposta simples: você não pode. Os elementos do formulário têm recursos de estilo muito limitados.

A melhor alternativa seria definir disabled=truea opção (e talvez uma cor cinza, já que apenas o IE faz isso automaticamente), e isso tornará a opção impossível de clicar.

Como alternativa, se você puder, remova completamente o optionelemento.

Niet the Dark Absol
fonte
6
// Simplest way

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

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

Como já está usando JS, você pode criar um elemento SELECT oculto na página e, para cada item que está tentando ocultar nessa lista, mova-o para a lista oculta. Dessa forma, eles podem ser facilmente restaurados.

Não sei como fazer isso em CSS puro ... Eu teria pensado que o truque display: none teria funcionado.

Derreck Dean
fonte
2

!!! AVISO !!!

Substitua o segundo "IF" por "WHILE" ou não funciona!

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
fonte
2

Você deve removê-los do <select>usando JavaScript. Essa é a única maneira garantida de fazê-los ir embora.

Jordânia
fonte
1
Usando jQuery, isso pode ser feito com remove:$('options').remove();
Luke
2

este parece funcionar para mim no cromo

$("#selectid span option").unwrap();
$("#selectid option:not([filterattr=filtervalue])").wrap('<span/>');
exilado
fonte
1
Adicione o formato do código ao seu código, recuando com 4 espaços ou envolvendo o código com `.
Banana
1
este código é ótimo! ele funciona no Chrome, Firefox e IE 11 mais recentes, isso é bom o suficiente para mim :)
Sijav
1
antes do meu último comentário, essa coisa funciona no IE 7 também! então ff 3.5, isso é o que eu criei no último, de alguma forma no IE e no cromo preserva o valor que foi selecionado antes que as opções sejam ocultadas e se outro valor não for definido após trazer de volta o navegador de opções irá definir a opção selecionado como antes!
Sijav
0

Atrasado para o jogo, mas a maioria parece bastante complicada.

Veja como eu fiz:

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

});

marcação de select-1:

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

marcação de select-2:

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