如何使用 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 请求或<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>
【讨论】:
以上是关于如何使用 Select2 和 Ajax 保留相关下拉值的主要内容,如果未能解决你的问题,请参考以下文章
如何将模型数据加载到在 Yii 中使用 Ajax 过滤的 Select2 下拉列表
如何使用 ajax (codeigniter) 在我的编辑表单中获取和显示选定值到 <select2> 标记中