2
votes

I have a dropdown select of optional 'opportunities' (id="opportunities" in the example below) which I enhance using the select2 jquery plugin, and wish to dynamically filter this list in order to reduce the possible options presented to a user using a 2nd select dropdown (id="group-select" in the example below),

<label>
  Select an opportunity<br>
  <select id="opportunities" style="width:300px;" multiple="multiple" name="selected-opps" value="">
    <optgroup label="Class A">
      <option class="group-1" value="1a">Opportunity 1a</option>
      <option class="group-2" value="2a">Opportunity 2a</option>
    </optgroup>
    <optgroup label="Class B">
      <option class="group-1" value="1b">Opportunity 1b</option>
      <option class="group-2" value="2b">Opportunity 2b</option>
    </optgroup>
    <optgroup label="Class C">
      <option class="group-1" value="1c">Opportunity 1c</option>
      <option class="group-2" value="2c">Opportunity 2c</option>
    </optgroup>
  </select>
</label>
<select id="group-select">
  <option value="">Select a group</option>
  <option value="group-1">group 1</option>
  <option value="group-2">group 2</option>
</select>
</div>
<div id="select-opportunity"></div>
<script type="text/javascript">
(function( $ ) {
  'use strict';

   var opportunities = $('select#opportunities').select2({
    dropdownParent: $('#select-opportunity')
  });
})( jQuery );
</script>

I wish to be able to make a selection in the 2nd select, say 'group 1' and would like the select2 list to contain only 'group-1' items as per the option in the first select dropdown that have the grouo-1 class attribute.

2

2 Answers

3
votes

I managed to solve this using 2 optional functionality provided by the select2 plugin, namely the ability to control the way items are built and displayed using the templating functionality, and using the programmatic control exposed in the plugin. I replaced the javascript appended below the example in the question with,

<script type="text/javascript">
(function( $ ) {
  'use strict';

  var opportunities = $('select#opportunities').select2({
    dropdownParent: $('#select-opportunity'),
    templateResult: formatItem
  });
  function formatItem (state) {
    if (!state.id) { return state.text; }
    //change the id of our select2 items
    state._resultId = state._resultId+'-'+state.element.className;
    var $state = $(
      '<span class="opportunity-item ' + state.element.className + '">' + state.text + '</span>'
    );
    return $state;
  }
  $('select#group-select').change( function() {
    //hide the unwanted options
    var group = $('select#group-select option:selected').val();
    //clear the styling element
    $('style#select2-style').empty();

    if(group){
      //if a group is selected we need to hide all the others
      $('select#group-select option').not(':selected').each(function(){
        group = $(this).val();
        if(group){
          $('style#select2-style').append(
           'li[id$="'+group+'"]{display:none;}'
          );
        }
      });
    }
    //force the select2 to referesh by opening and closing it again
    opportunities.select2('open');
    opportunities.select2('close');
  });


})( jQuery );
</script>
<style id="select2-style"></style>

I have also added an empty <style> element at the bottom in which I dynamically create the rules required to hide the unwanted items.

The logic

The code above creates templating function formatItem that the select2 plugin will use to format the items. The item state object is passed to the function which includes the unique id for each item.

This id is modified by appending the class of the corresponding option element.

When a group option is selected in the 2nd dropdown select (#group-select) a set of styling is created and appended to the bottom <style> element to hide all the elements whose id attributes end with the class names to be hidden, for example if one seleced group-1, the code will create a style to hide group-2 items,

li[id$="group-2"] { 
  display:none;
}

However for this to work we need to force the select2 dropdown to refresh to pick up the new styling and the only way I found for this work was to use the programmatic control of the plugin to 'open' and immediately 'close' the select2 dropdown.

-1
votes

ّshort Example .

window.templateResult = function templateResult(state) {
            if (state.text.indexOf('ss') == -1)
                return null;///hide

            if (!state.id) { return state.text; }
            var $state = $(
              '<span>' + state.text + '</span>'
            );
            return $state;
        };

        //Init
        $("#select1").select2({
            templateResult: templateResult
        });

ّFull Example below.

$(document).ready(function () {

            //general custom filter
            window.Select2FilterFunc = function (state) { return "Default" };

            //general custom templateResult
            window.templateResult = function templateResult(state) {

                //call custom filter
                var result = Select2FilterFunc(state);
                if (result != "Default")
                    return result;

                if (!state.id) { return state.text; }
                var $state = $(
                  '<span>' + state.text + '</span>'
                );
                return $state;
            };

            //Init
            $("#select1").select2({
                templateResult: templateResult
            });

            //Add Custom Filter when  opening
            $('#select1').on('select2:opening', function (evt) {

                //set your filter
                window.Select2FilterFunc = function (state) {
                    if (state.text.indexOf('ss') == -1)
                        return null;//hide item
                    else
                        return "Default";
                };

            }).on('select2:close', function (evt) {
                window.Select2FilterFunc = function (state) { return "Default" };
            });

        });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js"></script>

<select id="select1" class="js-states form-control" style="width:300px" multiple="multiple ">
        <optgroup label="Alaskan/Hawaiian Time Zone">
            <option value="AK" title="11111111">Alaska</option>
            <option value="HI" title="2222">Hawaii </option>
        </optgroup>
        <optgroup label="Pacific Time Zone">
            <option value="CA">California</option>
            <option value="NV">Nevada</option>
            <option value="OR">Oregon</option>
            <option value="WA">Washington</option>
        </optgroup>
        <optgroup label="Mountain Time Zone">
            <option value="AZ">Arizona</option>
            <option value="CO">Colorado</option>
            <option value="ID">Idaho</option>
            <option value="MT">Montana</option>
            <option value="NE">Nebraska</option>
            <option value="NM">New Mexico</option>
            <option value="ND">North Dakota</option>
            <option value="UT">Utah</option>
            <option value="WY">Wyoming</option>
        </optgroup>
        <optgroup label="Central Time Zone">
            <option value="AL">Alabama</option>
            <option value="AR">Arkansas</option>
            <option value="IL">Illinois</option>
            <option value="IA">Iowa</option>
            <option value="KS">Kansas</option>
            <option value="KY">Kentucky</option>
            <option value="LA">Louisiana</option>
            <option value="MN">Minnesota</option>
            <option value="MS">Mississippi</option>
            <option value="MO">Missouri</option>
            <option value="OK">Oklahoma</option>
            <option value="SD">South Dakota</option>
            <option value="TX">Texas</option>
            <option value="TN">Tennessee</option>
            <option value="WI">Wisconsin</option>
        </optgroup>
        <optgroup label="Eastern Time Zone">
            <option value="CT">Connecticut</option>
            <option value="DE">Delaware</option>
            <option value="FL">Florida</option>
            <option value="GA">Georgia</option>
            <option value="IN">Indiana</option>
            <option value="ME">Maine</option>
            <option value="MD">Maryland</option>
            <option value="MA">Massachusetts</option>
            <option value="MI">Michigan</option>
            <option value="NH">New Hampshire</option>
            <option value="NJ">New Jersey</option>
            <option value="NY">New York</option>
            <option value="NC">North Carolina</option>
            <option value="OH">Ohio</option>
            <option value="PA">Pennsylvania</option>
            <option value="RI">Rhode Island</option>
            <option value="SC">South Carolina</option>
            <option value="VT">Vermont</option>
            <option value="VA">Virginia</option>
            <option value="WV">West Virginia</option>
        </optgroup>
    </select>