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

Posted

技术标签:

【中文标题】如何使用 Select2 和 Ajax 保留相关下拉值【英文标题】:How to retain dependent dropdown values using Select2 and Ajax 【发布时间】:2022-01-05 15:16:44 【问题描述】:

我有一个脚本可以根据国家/地区 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>

因此,当我在第一次更改国家/地区选择之后调用它时,它会根据 localStorage 值选择国家并触发更改,但它不会对州做同样的事情,我在这里缺少什么想法吗?

【问题讨论】:

【参考方案1】:

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

【讨论】:

谢谢,这对我有用,但我认为我还需要在使用它后删除 localStorage 值,因为它会在打开另一个使用相同表单的表单时自动使用,你不会碰巧也有这个技巧? 在 if 语句中检查 page_load 是否为真,您可以添加 localStorage.clear(); 以便在附加选择框后清空本地存储数据。 不幸的是,这不起作用,因为如果在使用 php 提交时表单验证失败,那么我将失去选择,无法找到如何使用 PHP 传递 js 函数的方法【参考方案2】:

当我在第一次更改国家/地区选择之后调用它时,它会根据 localStorage 值选择国家并触发更改,但它不会对州做同样的事情,我在这里缺少什么想法?

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

当您触发 #state 列表的更改事件时紧接着,列表仍然是空的。不能选择任何值,因此 change 事件什么都不做。

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

// 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 请求或&lt;option&gt; 创建。

$("#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>

【讨论】:

以上是关于如何使用 Select2 和 Ajax 保留相关下拉值的主要内容,如果未能解决你的问题,请参考以下文章

Select2 ajax:在编辑模式下预选数据

如何将模型数据加载到在 Yii 中使用 Ajax 过滤的 Select2 下拉列表

如何使用 ajax (codeigniter) 在我的编辑表单中获取和显示选定值到 <select2> 标记中

ajax加载不同内容后如何刷新Select2下拉菜单?

如何使用 Select2.js 对从 Ajax 调用返回的数据进行多选结果?

保留 InitSelection -Select2