Select2: Hide certain options dynamically
Asked Answered
S

13

49

Basically what I'm looking for is the ability to hide options from the dropdown of select items. So, technically they would still be options, but you just wouldn't be able to click them since they're hidden.

I've looked through the docs and have found things related to disabling, unfortunately I very specifically want the ability to hide items. Does anyone have advice on how to accomplish this?

Were it possible to do something like have the select do some specific mapping between the original <option> element and the select2 copy of that element, that would work as well. As an example, say, "if the original <option> has such class or has such attribute, the resulting item in the select dropdown will be constructed this way".

Seabury answered 31/7, 2014 at 16:39 Comment(1)
In another question for the same problem, I gave this answer: https://mcmap.net/q/356414/-hiding-select2-options/… Hope can help. LucaAbfarad
H
58

Would adding the following CSS Rule to the page solve your problem?

.select2-container--default .select2-results__option[aria-disabled=true] {
    display: none;
}

Basically it would hide a disable option instead of displaying it with a gray background.

Use disabled instead of display:'none' in your options list also.

JS Bin

Hinterland answered 17/11, 2014 at 17:58 Comment(7)
Added edit, tested works in IE9, couldn't test in IE8 - can you let me know if it works in IE8 ?Hinterland
works perfectly for me. don't need to support non-browsers though.Malacostracan
I had to use [aria-seleted=true] instead of [aria-disabled=true]Prejudicial
your answer is probably the most relevant and precise solution for this problem. Been searching for more than an hour, only this worked for me on select2 with multiple selection enabled.Maemaeander
You should probably consider updating your answer. Your answer seems to be short and precise but the class="select2-container--default" does not seem to exist for me in the latest version of select2.Bivins
Had to use .select2-container .select2-results__option[aria-disabled=true] to get this to work for me.Hypotenuse
BEWARE! You need to exclude the hidden "load more" option or else any ajax enabled selects will continue to load pages without the user scrolling until they are exhausted when opened! .select2-results__options .select2-results__option[aria-disabled=true]:not(.select2-results__option--load-more)Ingravescent
A
28

I just invested 3 hours and found a very clean and easy solution for me dynamically showing/hiding options in a select2-container.

First, I create the select2 with this option:

$( selector ).select2({
  templateResult: resultState
});

Then I provide the resultState callback function which copies all classes from the original <option> to the select2-option. This allows us to show/hide options in select2 depending on the class we assign to the original option.

function resultState(data, container) {
    if(data.element) {
        $(container).addClass($(data.element).attr("class"));
    }
    return data.text;
}

In my css I declared this line:

.select2-container .select2-results__option.optInvisible {
    display: none;
}

Now I can easy show or hide hide any options in the select2-container by adding the optInvisible class to the <option>:

<select>
  <option class="optInvisible">Choose one</option>
  <option value="1">1</option>
</select>

Or you could also update it dynamically using addClass("optInvisible") or removeClass("optInvisible").

May this helps anyone ;) Greetings

Abeyance answered 9/4, 2019 at 12:57 Comment(5)
Hi. To whom yo add or remove class "optInvisibel" to the option tags? ThanksInsistence
Hi Tom, you assign the class 'optInvisible' to the <option>-Elements in the original <select> .. optInvisible = optionInvisible.. Of course only assign to be invisible ;)Abeyance
Nice solution, v.clean, tyLorsung
another option is to show show/hide the option directly via the style. $(container).hide().Hua
This solution has a shortcoming: when you type something in the dropdown search window the invisible options are still matching your search string, and if you click Enter, it will select the matched search option, even if it was invisible. To fix this, you need to make the select options disabled too: <option class="optInvisible" disabled="disabled">Choose one</option>Cobaltous
D
4

If you want to achieve it , maybe you can modify the select2.js code,

First i hidden the second option , originally it will not work when you use

select2 plugin ,

<select id="test" style="width:100px">
  <option></option>
  <option value='1'>1</option>
  <option value='2' style="display:none">2</option>
</select>

Second i will modify the select2.js code: line 926

i add extra condition statement && element.css('display') != 'none' here

 process = function (element, collection) {
     var group;
     if (element.is("option") && element.css('display') != 'none') {
         if (query.matcher(term, element.text(), element)) {
              collection.push(self.optionToData(element));
              }
     } else if (element.is("optgroup")) {
              group = self.optionToData(element);
              element.children().each(function (i, elm) { 
                       process(elm, group.children); 
                   });
              if (group.children.length > 0) {
                       collection.push(group);
              }
      }
     };

JSBIN http://jsbin.com/qusimi/1/edit

Daphnedaphnis answered 1/8, 2014 at 16:48 Comment(2)
You should not suggest to modify external libraries (without contributing to original).Loquacious
and every time you run npm update or equivalent, keep updating the select2.js? That's not how things should be done at all!Cyanohydrin
U
4

I had a similar requirement. Hiding was preferred, but many of these answers were uncertain for several browsers or too complicated. Changing select2 code was also out of the question.

My solution was to store a copy of the options for each select in memory as an array. When I wanted to "hide" an option, i would use jQuery remove(). When I wanted to "unhide", I would re-add it to that select's options.

Remember to call .trigger("change") on the select if it is possible you are hiding an option that might be currently selected.

Uncleanly answered 21/1, 2018 at 2:9 Comment(0)
N
3
$('.selector').remove(); 

And then append the option according to position it appear in select2 :

To appear as first option then :

$('.selector')
.prepend('<option value="option-value" class="option-value">Option Label</option>');

To appear as last option then :

$('.selector')
.append('<option value="option-value" class="option-value">Option Label</option>');

To appear as after any of the option then :

$('<option value="option-value" class="option-class">Option Label</option>')
.insertAfter($('.selector option:first-child'));

Or

$('<option value="option-value" class="option-value">Option Label</option>')
.insertAfter($('.selector > .option-class'));

OR

We can disable/enable the option using jquery, instead of hiding.

$('.selector').prop('disabled', 'disabled');

$('.selector')
.prop('disabled', !$('.selector').prop('disabled'));
Nakesha answered 26/2, 2016 at 11:8 Comment(0)
R
3

This is an update to the answer by @peter-schilling, because the Select2 templating API seems to have altered since he posted it.

I needed to dynamically show and hide options in a select which was being targeted by Select2, so I initialised Select2 like this:

$("#myDropdown").select2({
    ...
    templateResult: function (state) {
        let $opt = $(state.element);
        if ($opt.hasClass("d-none")) {
            return null;
        }
        return state.text;
    }
});

Here I've used the d-none utility class from Bootstrap, but you could easily use your own CSS class (or any other attribute on the <option> element, for that matter) that identified that an option should be hidden.

Since I was setting this class dynamically on my base <select> element's <option>s I then had to reinitialise Select2 each time, which I did thus:

$("#myDropdown").select2("destroy");
$("#myDropdown").select2(select2Options);

(I store my Select2 configuration options in a Javascript object as a global variable called select2Options and then use them like this anywhere I initialise Select2, since I want the behaviour to be consistent throughout my application.)

Recrement answered 14/9, 2021 at 19:54 Comment(0)
T
1

this is small varation of the accepted answer, actually I had to modify the accepted answer to make it work, I had to change the class names, maybe this is because different versions of Select2 library

.select2-results__options .select2-results__option[aria-disabled=true] {
   display: none;
}
Tedesco answered 17/2, 2017 at 14:35 Comment(1)
@KazimZaidi try the most up-voted answer, and if it did not works for your try the other answersQuillet
S
1

a simple:

.select2-results .select2-disabled { display: none }

worked for me

Style answered 2/2, 2023 at 16:18 Comment(0)
L
0

This code works. Tested with version Select2 4.0.6

    <select class='select2'>
        <option>WillShow</option>
        <option willHide='true'>WillHide</option>
    </select>

    <style>
        li[aria-disabled='true'] {
            display: none;
        }
    </style>

    <script type="text/javascript">
        $(".select2").select2();
        $(".select2 option[willHide='true']").prop("disabled", true);
    </script>
Lazaro answered 29/10, 2019 at 0:12 Comment(0)
W
0

I just made a variation of he answer 6 and changed class by hidden attribute, so this way every option with hidden attribute will also be hidden in a select2 container like below that the option 1 will be hidden:

<select class='mySelect'> My Select 2
<option hidden>1</option>
<option >2</option>
<option >3</option>
</select>

$('.mySelect').select2({templateResult: hideSelect2Option});

function hideSelect2Option(data, container) {
    if(data.element) {
        $(container).addClass($(data.element).attr("class"));
        $(container).attr('hidden',$(data.element).attr("hidden"));
    }
    return data.text;
}

   
Worden answered 16/7, 2020 at 11:38 Comment(0)
F
0

If somebody wants a another option using jquery data tags this woks for me:

$('.select2 option').each(function(){
        if ($(this).data('condition') != 'true' ) {
          $(this).wrap('<div></div>')
        } else {
          $(this).unwrap('div')
        }
})
Frisky answered 5/11, 2020 at 10:40 Comment(0)
C
0

I had a situation where needed to click on a 'role' button from a list of roles and then to open a modal in which I had to select any another role from which to copy permissions to the current clicked one (laravel 8 project, latest jQuery). Sending the current clicked role via data attribute to add to modal hidden input, I built the select using jQuery not adding the current role option (not displaying at all) and then called select2 for initialization.

The button:

<i class="fas fa-download cursor-pointer" data-copy-permissions="10" 
data-toggle="modal" data-target="#copy_permissions"></i>

Modal form elements:

<input type="hidden" name="current_role_id" value="">
<select name="copy_role_id" id="copy_role_id" style="width: 100%"></select>

DOM manipulation (I also had select optgroups but it doesn't matter to the discussion):

$("[data-copy-permissions]").on('click touch', function() {
        let current_role_id = $(this).data('copy-permissions');
        $('input[name="current_role_id"]').val(current_role_id);
        let roles_select = $('select[name="copy_role_id"]').html("");
        let option = "";

        @foreach ($rolesTree as $section)
            option = '<optgroup label="{{ $section['section']->label }}">';
                @foreach ($section['subroles'] as $subrole)
                    if(current_role_id != '{{ $subrole->id }}') {
                        option += '<option value="{{ $subrole->id }}">{{ ucfirst($subrole->name) }}</option>';
                    }
                @endforeach
            option += '</optgroup>';
            roles_select.append(option);
        @endforeach

        roles_select.select2();
    });
Clova answered 9/9, 2021 at 15:24 Comment(0)
H
0

None of the above solutions worked for me (might be because) due to the infinite scroll capability in my select2. Hence I would intersept the processResults attribute event and filter the incoming set of data and then feed it to the options. Below is my select2 for your reference:

My problem: I wanted to filter the drop down options to not show values already selected that was being displayed already in an

$('##selectRoles').select2({
        ajax: {
            url: '/url',
            dataType: 'json',
            delay:250,
            data: function (params) {
                var queryParameters = {
                    searchParam: params.term
                    
                    
                }
                return queryParameters;
            },
            processResults: function (data,params) {

                var listOfSelectRolesArray = [];
                var dataToFilter = data.data; 
                $('##listOfSelectRoles li a').each(function(d,x){
                    listOfSelectRolesArray.push(x.attributes['data-overlay'].value);
                });
                
                var filtered = dataToFilter.filter(function(item) {
                    return listOfSelectRolesArray.indexOf(item.id) == -1;
                });
                    params.page =   params.page || 1;
                    return {
                    results: filtered,
                    pagination: {
                            more: (params.page * 10) < data.recordsTotal
                        }
                    };
                },
        },
        placeholder: "Select a role",
        allowClear: true,
        forceabove:false,
        maximumInputLength: 20,
        minimumResultsForSearch: 20,
        multiple:true,
        sorter: data => data.sort((a,b) => a.text.toLowerCase() > b.text.toLowerCase() ? 0 : -1)
        });
Havelock answered 8/6, 2023 at 12:45 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.