Chaining multiple Select2 together

I Test picture I Test · May 14, 2015 · Viewed 16.2k times · Source

Trying to make two chained auto populating select fields using select2 plugin The first select contains countries names(static select) and the second shows the states of the country selected from the first select my code is

<select id="country" name="country" size="1" class=" form-control">
<option></option>
<option value="1">USA</option>
<option value="2">Untied Kingdom</option>
<option value="3">France</option>
etc........
</select>
<select id="states" name="states" size="1" class="form-control">
<option></option>
</select>

The JavaScript Code

$(document).ready(function() {
    $('#country').select2({
        placeholder: 'Select Country',
        allowClear: true
    });
    $('#state').select2({
        placeholder: 'Select State',
        allowClear: true
    });
    $('#country').change(function() {
            var selectedCountries = $('#countryoption:selected').val();
            var selectedCountries = 'id='+ selectedCountries;
            $.ajax({
                type: 'POST',
                url: 'http://localhost/CodeIgniter/countries/get_state/',
                dataType: 'html',
                data: selectedCountries,
                }).done( function( data ) {
                       data = $.map(data, function(item) {
                            return { id: item.id, text: item.name }; 
                        });
                        $('#state').select2({
                            data: data
                        });
                }
            })
    });
});

The Returened Results in JSON

{"id":"1","text":"Chigaco"}{"id":"4","text":"Albama"}{"id":"2","text":"Tulsa"} etc...........

I searched a lot for an example to help me with this but nothing working right all I need is to show the states of the country chosen in the first select and pass it to the second select known that I'm using select2 v4.0 and jquery v2

Answer

Kevin Brown picture Kevin Brown · May 15, 2015

A Select2 can be chained in the same way that a standard <select> can be chained. So that means that when the value of the first select is chained, the second select is reset (generally to a placeholder) and the options generally change as well.

You have two options for how this can be done with Select2:

  1. Pre-load the options for the second <select> when the value changes, and let Select2 handle searching locally. This would be similar to how you are currently trying to do it, but may suffer from issues when there are a large number of options that can be selected in the second <select>.

    In your case, there shouldn't be thousands of "states" (for whatever degree of state) within a country, so local searching shouldn't be too much of an issue.

  2. Use Select2's AJAX functionality and pass in a different parameter as the url to use based on the value of the first <select>. This requires that you have a dynamic endpoint that can handle retrieving the items for the second select as well as filtering them when searching, so it's not always feasible.

    If you already have an endpoint like this that supports filtering, this is a more responsive option as the user doesn't have to necessarily wait for all options to be retrieved before they can select an option from the second <select>.

What option you choose largely depends on what you already have set up, the size of the data set that you are working with (Select2 does not handle well with thousands of options), and the user experience you want to provide.

The code for the first option would be similar to

$("#first").select2({
  placeholder: 'Select a number range'
});

$("#second").select2({
  placeholder: 'Select a number'
});

$("#first").on("change", function () {
  $("#second option[value]").remove();
  
  var newOptions = []; // the result of your JSON request

  $("#second").append(newOptions).val("").trigger("change");
});

And can be tested at the following jsbin, using ranges of numbers instead of countries and states: http://jsbin.com/wigalivapi/1/edit?html,output

Note that while this is similar to the code you were using, there are a few small difference that would have caught you.

  1. You are setting dataType: "html" when you are really expecting dataType: "json". You are returning JSON in your response, not HTML.

  2. You are not clearing your <select> before you call .select2({data:[]}) a second time. Select2 doesn't automatically remove the <option> tags it generates with data, so you need to do that on your own.

  3. When you change the value of the <select>, you never tell Select2 about it. You need to re-trigger the change event on the second <select> after you change it.

  4. The JSON that you provide in your question does not appear to be valid. Now I'm not sure if that is just because you are giving it as an example, but I would check your JSON response with JSONLint just to ensure that it is valid.

The code for the second option would be similar to

$("#first").select2({
  placeholder: 'Select a number range'
});

$("#second").select2({
  placeholder: 'Select a number',
  ajax: {
    url: http://localhost/CodeIgniter/countries/get_state/',
    type: 'POST',
    data: function (params) {
      return {
        id: $("#first").val(),
        search: params.term
      }
    }
  }
});

And this can be tested at the following jsbin, which mocks the response using a range of numbers (similar to the other example): http://jsbin.com/gihusohepe/1/edit?html,output