如何使用 Select2 和 Ajax 保留相关的下拉值

How to retain dependent dropdown values using Select2 and Ajax

我有一个脚本可以根据国家/地区 ID 填充状态下拉列表,虽然一切正常,但我只能在页面重新加载时保存国家/地区下拉选项,而不是使用 html localStorage 的状态选项。

这是我的代码:

$(document).ready(function() {
  var country_id = null;
  var state_id = null;

  $('#country').select2();
  $('#state').select2();
  $('#city').select2();

  $('select[name="country"]').on('change', function() {
    var country_id = $(this).val();
    if (country_id) {
      $.ajax({
        url: "/world/getStates.php",
        type: "GET",
        data: {
          'country_id': country_id
        },
        dataType: "json",
        success: function(data) {
          $('select[name="state"]').empty();
          $('select[name="city"]').empty();
          $('select[name="state"]').append('<option value="">Select State</option>');
          $.each(JSON.parse(data), function(key, value) {
            $('select[name="state"]').append('<option value="' + value.id + '">' + value.name + '</option>');
          });
        }
      });
    } else {
      $('select[name="state"]').empty();
    }
  });

  $('select[name="state"]').on('change', function() {
    var country_id = $('#country').val();
    var state_id = $(this).val();
    if (state_id) {
      $.ajax({
        url: "/world/getCities.php",
        type: "GET",
        data: {
          'country_id': country_id,
          'state_id': state_id
        },
        dataType: "json",
        success: function(data) {
          $('select[name="city"]').empty();
          $('select[name="city"]').append('<option value="">Select City</option>');
          $.each(JSON.parse(data), function(key, value) {
            $('select[name="city"]').append('<option value="' + value.id + '">' + value.name + '</option>');
          });
        }
      });
    } else {
      $('select[name="city"]').empty();
    }
  });

  $('#country').val("value from localStorage").trigger('change');
  $('#state').val("value from localStorage").trigger('change');
});
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/css/select2.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/js/select2.min.js"></script>

<label for="country">Country</label>
<select class="csc-select" name="country" id="country">
  <option value="">Select Country</option>
  <option>Australia</option>
  <option>Denmark</option>
  <option>Japan</option>
  <option>Norway</option>
  <option>Switzerland</option>
</select>

<label for="state">State</label>
<select class="csc-select" name="state" id="state">
  <option value="">Select State</option>
</select>

<label for="city">City</label>
<select class="csc-select" name="city" id="city">
  <option value="">Select City</option>
</select>

因此,当我在国家 select 的第一次更改后调用它时,它 select 是基于 localStorage 值的国家并触发更改,但它不会对状态,我在这里缺少什么想法?

状态下拉列表中的选项在 ajax 成功执行后加载,因此您的其他代码不会等待它并且 .val() 之前触发,这就是该值未标记为的原因在状态下拉列表中选择。现在,要解决此问题,您可以将该部分移动到 ajax 的成功函数中,然后在选项附加到状态下拉列表中后调用您的更改事件。

演示代码 :

$(document).ready(function() {

  var country_id = 1 //localStorage.getItem("select2CountryValue");
  var state_id = 3 //localStorage.getItem("select2StateValue");
  var page_load = true; //added this 
  var data = [{
    "id": 1,
    "name": "xyz_State1"
  }, {
    "id": 2,
    "name": "xyz_State2"
  }, {
    "id": 3,
    "name": "xyz_State3"
  }] //this is just the demo datas
  $('#country').select2();
  $('#state').select2();

  $('select[name="country"]').on('change', function() {
    var country_id = $(this).val();
    //localStorage.setItem("select2CountryValue", country_id);
    if (country_id) {
      /*$.ajax({
        url: "/world/getStates.php",
        type: "GET",
        data: {
          'country_id': country_id
        },
        dataType: "json",
        success: function(data) {
          console.log(data);
          $('select[name="city"]').empty();*/
      $('select[name="state"]').empty();
      $('select[name="state"]').append('<option value="">Select State</option>');
      $.each(data, function(key, value) {
        $('select[name="state"]').append('<option value="' + value.id + '">' + value.name + '</option>');
      });
      //check if the change is called on page load
      if (page_load == true) {
        $('#state').val(state_id).trigger('change'); //assign slected value after elemnt option is added in dom
        page_load = false; //add this so that next time this doesn't get execute
      }
      /* }
        });*/
    } else {
      $('select[name="state"]').empty();
    }
  });

  $('#country').val(country_id).trigger('change');

});
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/css/select2.min.css" />
<script src="https://code.jquery.com/jquery-3.2.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/js/select2.full.min.js"></script>

<p>
  <span>Country</span>
  <select class="csc-select" name="country" id="country">
    <option value="">Select Country</option>
    <option value="1">
      xyz
    </option>
    <option value="2">
      xyz2
    </option>
  </select>
</p>
<p>
  <span>State</span>
  <select class="csc-select" name="state" id="state">
    <option value="">Select State</option>
  </select>
</p>

when I call this after the first on change for the country select, it selects the country based on the localStorage value and triggers the change but it does not do the same for the state, any ideas what I am missing here?

当您触发 #country 列表的更改事件时,国家/地区列表已包含值。

当您触发#state列表的更改事件之后,列表仍然是空的。不能选择任何值,因此更改事件不执行任何操作。

您需要等到状态列表被填充,然后触发更改事件。

// this works immediately, because there are countries in your HTML
$('#country').val("value from localStorage").trigger('change');

// this needs to happen in the `success` callback of country Ajax call
$('#state').val("value from localStorage").trigger('change');

另一种方法是先创建一个临时选项:

$('#state').append("temporary <option> created from localStorage");
$('#state').val("value from localStorage").trigger('change');

这样就不用等了


也就是说,Select2 支持 remote data,您不必自己编写 Ajax 请求或 <option> 创建。

$("#country").select2({
  ajax: {
    url: "/world/getCountries.php"
  },
  placeholder: 'Pick a country',
  minimumInputLength: 1
}).change(function () {
  $("#state").val("").trigger("change");
});

$("#state").select2({
  ajax: {
    url: "/world/getStates.php",
    data: (params) => {
      // add selected country ID to URL params 
      params.country_id = $("#country").val();
      return params;
    }
  },
  placeholder: 'Pick a state',
  minimumInputLength: 1
});

// initialize selection from previous state...
$("#country").append('<option value="5">Switzerland</option>');
$("#country").val("5");
$("#state").append('<option value="9">Appenzell</option>');
$("#state").val("9");


// server side mock-up -------------------------------------------------
const countries = [
  {id: 1, text: 'Australia'},
  {id: 2, text: 'Denmark' },
  {id: 3, text: 'Japan'},
  {id: 4, text: 'Norway'},
  {id: 5, text: 'Switzerland'}
];
const states = [
  {id: 1, text: 'New South Wales', country_id: 1},
  {id: 2, text: 'Victoria', country_id: 1},
  {id: 3, text: 'Hovedstaden', country_id: 2},
  {id: 4, text: 'Midtjylland', country_id: 2},
  {id: 5, text: 'Hokkaido', country_id: 3},
  {id: 6, text: 'Shikoku', country_id: 3},
  {id: 7, text: 'Northern Norway', country_id: 4},
  {id: 8, text: 'Southern Norway', country_id: 4},
  {id: 9, text: 'Appenzell', country_id: 5},
  {id: 10, text: 'Zürich', country_id: 5},
];

$.mockjaxSettings.logging = 1;
$.mockjax({
  url: "/world/getCountries.php",
  contentType: "application/json",
  response: function(settings) {
    this.responseText = {
      results: countries.filter(item =>
        !settings.data.term || item.text.toLowerCase().includes(settings.data.term.toLowerCase())
      )
    };
  }
});
$.mockjax({
  url: "/world/getStates.php",
  contentType: "application/json",
  response: function(settings) {
    console.log(settings.data);
    this.responseText = {
      results: states.filter(item =>
        item.country_id == settings.data.country_id && (
          !settings.data.term || item.text.toLowerCase().includes(settings.data.term.toLowerCase())
        )
      )
    };
  }
});
select {
  width: 200px;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/css/select2.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/js/select2.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-mockjax/2.6.0/jquery.mockjax.min.js"></script>

<select id="country"></select>
<select id="state"></select>