jQuery UI AutoComplete多值选择时删改值同步隐藏域方案
问题说明
现有实现
通过可见文本框实现城市多选自动补全,搭配隐藏域存储选中城市对应的ID,基础HTML结构如下:
<label class="col-sm-2 control-label" for="city_disp"> City</label> <div class="col-sm-5"> <div class="input-group"> <input type="hidden" class="hidden_value" name="city" id="city" value="" /> <input type="text" name="city_disp" placeholder="City" id="city_disp" data-request_type="cities" value="" class="form-control autocomplete-input-field" autocomplete="off" /> </div> </div>
当前基于jQuery UI AutoComplete实现补全逻辑,数据源通过Ajax拉取:
function split( val ) { return val.split( /,\s*/ ); } function extractLast( term ) { return split( term ).pop(); } $(".autocomplete-input-field").autocomplete({ source: function (request, response) { $this = this.element; var term = extractLast(request.term); $.ajax({ url: myHome+'/my_ajax', dataType: "json", type: "POST", data: { term: term, action_type: "getdata" }, success: function (data) { response(data); } }); }, minLength: 2, select: function (event, ui) { var tempval = $(this).val() ; var terms = split( this.value ); var split_string = split( $(this).closest('div').find('.hidden_value').val() ); split_string.pop(); terms.pop(); terms.push( ui.item.label ); split_string.push( ui.item.value ); terms.push( "" ); split_string.push( "" ); var labels = terms.join( ", " ); var new_vals = split_string.join( "," ); $(this).val(labels); $(this).closest('div').find('.hidden_value').val(new_vals); return false; }, focus: function (event, ui) { event.preventDefault(); } });
当前效果
- 可见输入框输入≥2个字符时自动补全正常触发
- 从下拉列表选中城市后,名称按逗号拼接显示在可见框,对应ID按相同顺序拼接存入隐藏域,例如选中
New York,Washington,London时,隐藏域值为45,56,78
待解决问题
- 用户手动删除可见框中某个中间项(如删除Washington)时,隐藏域ID列表未同步删除对应值,需要实现自动同步为
45,78 - 用户将已选城市修改为无匹配的无效字符(如
dasdsad)时,需要对应的适配处理逻辑
解决方案
原有逻辑仅在下拉选项选中事件中更新隐藏域,未覆盖手动编辑场景,通过以下改造即可实现需求:
- 新增本地缓存存储所有已加载的城市名-ID映射,避免校验时重复发起请求
- 抽离统一的同步校验方法,在选中选项、输入内容、输入框失焦时全量校验输入内容,对齐可见值与隐藏域ID
- 提供无效输入的可配置处理逻辑
完整改造代码如下:
// 城市名-ID映射缓存 const cityMap = {}; function split( val ) { return val.split( /,\s*/ ); } function extractLast( term ) { return split( term ).pop(); } /** * 同步校验输入框城市名,更新隐藏域ID * @param {HTMLElement} inputEl 自动补全输入框DOM */ function syncHiddenCityField(inputEl) { const $input = $(inputEl); const $hidden = $input.closest('.input-group').find('.hidden_value'); const rawValue = $input.val().trim(); // 拆分输入的城市列表,过滤空项 const cityNameList = split(rawValue).filter(name => name.trim().length); const validCityIds = []; const validCityNames = []; let hasInvalidInput = false; cityNameList.forEach(name => { const formatName = name.trim().toLowerCase(); // 匹配缓存中的有效城市 if (cityMap[formatName]) { validCityIds.push(cityMap[formatName]); validCityNames.push(name.trim()); } else { hasInvalidInput = true; } }); // 无效输入处理 if (hasInvalidInput) { // 加错误样式提示(可自定义CSS样式,比如红边框、提示文字) $input.addClass('input-error'); // 若需要自动过滤无效值,保留下面这行;若需要保留用户输入让其手动修改,注释即可 $input.val(validCityNames.join(', ')); } else { $input.removeClass('input-error'); } // 隐藏域仅存储有效城市ID $hidden.val(validCityIds.join(',')); } // 初始化自动补全 $(".autocomplete-input-field").autocomplete({ source: function (request, response) { const searchTerm = extractLast(request.term); if (searchTerm.length < 2) { response([]); return; } $.ajax({ url: myHome + '/my_ajax', dataType: "json", type: "POST", data: { term: searchTerm, action_type: "getdata" }, success: function (data) { // 将返回的城市数据存入本地缓存 data.forEach(item => { cityMap[item.label.trim().toLowerCase()] = item.value; }); response(data); } }); }, minLength: 2, select: function (event, ui) { event.preventDefault(); const terms = split(this.value); terms.pop(); terms.push(ui.item.label); terms.push(""); $(this).val(terms.join(", ")); // 选中后触发同步 syncHiddenCityField(this); return false; }, focus: function (event, ui) { event.preventDefault(); } // 绑定输入、失焦事件,编辑时自动同步 }).on('input blur', function () { syncHiddenCityField(this); });
无效输入场景可选处理方案
根据业务需求三选一即可:
- 自动过滤:即示例代码默认逻辑,失焦/输入时自动清除无效字符,仅保留有效城市,隐藏域同步存储有效ID,搭配错误样式临时提示
- 手动修正:保留用户输入的无效内容,持续展示错误样式,隐藏域仅存储当前有效项ID,阻塞表单提交直到用户修正所有无效值
- 强提示:检测到无效输入时直接弹出文字提示,告知用户存在未识别的城市名,请从下拉列表选择
内容的提问来源于stack exchange,提问作者SAYUJ RAGHAVAN
相关产品推荐
相关产品推荐

