如何动态使用Tom-select?克隆行组件失效问题排查与解决
问题描述
在模态框的表格中嵌入Tom-select输入组件,添加按钮用于新增该行,但点击按钮克隆包含Tom-select的行后,新行中的Tom-select无法正常工作,相关代码如下,如何实现Tom-select的动态初始化?
原代码
模态框渲染代码
// show modal : this.show = function(){ var main = this; var items= main.items; var modalTitle = "modalTitle"; var modalMsg = ' <div id="modal-id">'; modalMsg += ' <table id = "MyTable" class="table">'; modalMsg += ' <tbody>'; modalMsg += ' <tr>'; modalMsg += ' <th class="col-xs-3"> 25125211 : </th>'; modalMsg += ' <td class="col-xs-9"><label class="col-xs-3"><input type="radio" class="input-val" name="confirm_radio" id="approve" value="100" required>apporve</label>'; modalMsg += ' <label class="col-xs-3"><input name="confirm_radio" id="refer" type="radio" value="900" required>refer</label></td>'; modalMsg += ' </tr>'; modalMsg += ' <tr id = "tomselect-tr">'; modalMsg += ' <th class="col-xs-3"> chooseTomselectOption </th>'; modalMsg += ' <td>'; modalMsg += ' <div class="input-group"><select id="TomSelect_1" placeholder="choose an item..."></select><span class="input-group-btn"><button id="cloneTr" type="button" class="btn btn-tool"><i class="fa fa-plus"></i></button></span></div>'; modalMsg += ' </td>'; modalMsg += ' </tr>'; modalMsg += ' </tbody>'; modalMsg += ' </table>'; modalMsg += ' </div>'; var modalBtn1Text = "done"; var modalBtn2Text = "cancel"; var modalCallback; var updateCallback = function(){ agreementInfo.saveInfo(); }; modalCallback = updateCallback; this.modal = new _modal.show(modalTitle ,modalMsg ,modalBtn1Text ,modalBtn2Text ,modalCallback ); }
克隆行函数
// cloneTr function : function cloneTr(){ trNum++; var $newTr= $("#tomselect-tr").clone(); $newTr.attr("id", "tomselect-tr"+trNum); $newTr.find("#TomSelect_1").attr("id","TomSelect_"+trNum); $("#MyTable").find("tbody").find("#tomselect-tr").after($newTr); var targetDiv = "TomSelect_"+trNum; addSelector(targetDiv); }
Tom-select初始化函数
// addSelector function function addSelector(_targetDiv){ var selector = new TomSelect("#"+_targetDiv,{ valueField: 'USR_NO', searchField: ['USR_NM', 'USR_ID', 'USR_EMAIL', 'GP_NM'], maxItems: 1, maxOptions: 100, options: items, render: { option: function(data, escape) { console.log(escape); return '<div>' + ' <span class="USR_NM">' + escape(data.USR_NM) + '</span>' + ' <span class="GP_NM">' + escape(data.GP_NM) + '</span>' + ' <span class="USR_ID">' + escape(data.USR_ID) + '</span>' + ' <span class="USR_EMAIL">' + escape(data.USR_EMAIL) + '</span>' + '</div>'; }, item: function(data, escape) { return '<div id="'+itemDivTxt+'" title="' + escape(data.USR_NO) + '" data-name="' + escape(data.USR_NM) + '">' + ' <span class="tom-select-name">' + escape(data.USR_NM) + '</span>' + ' <span class="tom-select-group">' + escape(data.GP_NM) + '</span>' + '</div>'; } } }); selector.clearCache(); }
问题根源
克隆已初始化Tom-select的行时,原始<select>元素已经被Tom-select替换成了自定义的DOM结构(包含div、input等),克隆出来的不是真正的<select>,自然无法被Tom-select重新初始化。另外代码中itemDivTxt变量未定义,也会导致初始化报错。
解决方案
1. 保存原始select模板
在初始化第一个Tom-select前,保存原始<select>的HTML结构作为模板,避免克隆已被修改的DOM:
this.show = function(){ var main = this; var items= main.items; var modalTitle = "modalTitle"; var modalMsg = ' <div id="modal-id">'; modalMsg += ' <table id = "MyTable" class="table">'; modalMsg += ' <tbody>'; modalMsg += ' <tr>'; modalMsg += ' <th class="col-xs-3"> 25125211 : </th>'; modalMsg += ' <td class="col-xs-9"><label class="col-xs-3"><input type="radio" class="input-val" name="confirm_radio" id="approve" value="100" required>apporve</label>'; modalMsg += ' <label class="col-xs-3"><input name="confirm_radio" id="refer" type="radio" value="900" required>refer</label></td>'; modalMsg += ' </tr>'; modalMsg += ' <tr id = "tomselect-tr">'; modalMsg += ' <th class="col-xs-3"> chooseTomselectOption </th>'; modalMsg += ' <td>'; modalMsg += ' <div class="input-group"><select id="TomSelect_1" placeholder="choose an item..."></select><span class="input-group-btn"><button type="button" class="btn btn-tool clone-btn"><i class="fa fa-plus"></i></button></span></div>'; modalMsg += ' </td>'; modalMsg += ' </tr>'; modalMsg += ' </tbody>'; modalMsg += ' </table>'; modalMsg += ' </div>'; var modalBtn1Text = "done"; var modalBtn2Text = "cancel"; var modalCallback; var updateCallback = function(){ agreementInfo.saveInfo(); }; modalCallback = updateCallback; this.modal = new _modal.show(modalTitle, modalMsg, modalBtn1Text, modalBtn2Text, modalCallback); // 保存原始select的HTML作为模板,并初始化第一个Tom-select const originalSelectHtml = $("#TomSelect_1").prop('outerHTML'); window.tomSelectTemplate = originalSelectHtml; addSelector("TomSelect_1"); // 绑定第一个克隆按钮的点击事件 $(".clone-btn").on("click", cloneTr); }
2. 修改克隆逻辑,基于模板创建新行
不再克隆已初始化的行,而是用模板生成新的<select>元素,确保每次初始化的都是原始的select:
// 初始化trNum为1,确保新行ID从2开始 let trNum = 1; function cloneTr(){ trNum++; // 克隆原始行结构 const $newTr = $("#tomselect-tr").clone(); $newTr.attr("id", `tomselect-tr${trNum}`); // 用模板生成新的select,替换行内的select容器内容 const newSelectHtml = window.tomSelectTemplate.replace(/TomSelect_1/g, `TomSelect_${trNum}`); $newTr.find(".input-group").html(newSelectHtml + '<span class="input-group-btn"><button type="button" class="btn btn-tool clone-btn"><i class="fa fa-plus"></i></button></span>'); // 添加新行到表格 $("#MyTable tbody").append($newTr); // 初始化新的Tom-select addSelector(`TomSelect_${trNum}`); // 给新的克隆按钮绑定事件 $newTr.find(".clone-btn").on("click", cloneTr); }
3. 修复Tom-select初始化函数的报错
移除未定义的itemDivTxt变量,改用DOM元素直接初始化Tom-select(比选择器字符串更可靠):
function addSelector(_targetDiv){ const $select = $("#" + _targetDiv); // 确保目标select存在 if (!$select.length) return; var selector = new TomSelect($select[0], { valueField: 'USR_NO', searchField: ['USR_NM', 'USR_ID', 'USR_EMAIL', 'GP_NM'], maxItems: 1, maxOptions: 100, options: items, render: { option: function(data, escape) { return '<div>' + ' <span class="USR_NM">' + escape(data.USR_NM) + '</span>' + ' <span class="GP_NM">' + escape(data.GP_NM) + '</span>' + ' <span class="USR_ID">' + escape(data.USR_ID) + '</span>' + ' <span class="USR_EMAIL">' + escape(data.USR_EMAIL) + '</span>' + '</div>'; }, item: function(data, escape) { // 移除未定义的itemDivTxt,保留必要的属性 return '<div title="' + escape(data.USR_NO) + '" data-name="' + escape(data.USR_NM) + '">' + ' <span class="tom-select-name">' + escape(data.USR_NM) + '</span>' + ' <span class="tom-select-group">' + escape(data.GP_NM) + '</span>' + '</div>'; } } }); selector.clearCache(); }
内容的提问来源于stack exchange,提问作者강성빈
相关产品推荐
相关产品推荐

