You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Select2重选选项抛出Cannot read properties of undefined (reading 'id')错误

Select2 重选值时报错 Cannot read properties of undefined (reading 'id') 修复方案

问题根因

从报错栈定位到的setClasses方法逻辑可见,报错直接原因是遍历下拉选项节点时,从DOM节点读取绑定的选项数据得到undefined,后续访问c.id时触发类型错误。该问题和组件是否放在Bootstrap Modal内无强绑定关系,Modal场景仅会提升问题出现概率,核心触发原因共三类:

  • 选项数据格式不合法:Select2内部约定所有选项(静态option、动态加载项、默认选中项)必须携带非空唯一的id字段与展示用的text字段,任意一个选项缺失id,在做选中态匹配时都会触发该报错。
  • 组件状态不同步:直接操作原生select节点增删option、修改selected属性后,未调用Select2的同步方法更新内部缓存数据,导致组件持有的选项列表和实际DOM绑定的数据不一致,遍历到未绑定数据/已销毁的选项节点时读不到有效数据。
  • 层级/版本冲突:旧版Select2(4.0.12及以下)默认把下拉面板append到body节点,在Bootstrap Modal等带z-index层级、全局事件拦截的容器内使用时,会出现事件绑定丢失、选项data未正确挂载的问题;搭配jQuery 2.1.x版本时,jQuery本身的data缓存泄漏问题也会导致节点绑定的数据丢失。

可行解决方案

按排查优先级从高到低处理:

  • 校验全量选项格式
    静态渲染的option标签必须携带value属性(对应Select2内部的id字段),禁止出现无value的空option:
    <!-- 错误写法 -->
    <!-- <option>测试选项</option> -->
    <!-- 正确写法 -->
    <option value="1">测试选项</option>
    
    动态传入的data数组、ajax接口返回的选项列表,每一项必须包含非空id和text字段,禁止传null、undefined、空字符串作为id值,若需要保留空选项,统一将id设为0或约定的特殊字符串如'__empty__':
    // 错误写法
    // [{text: '选项1'}]
    // 正确写法
    const optionList = [
      {id: '1', text: '选项1'},
      {id: '2', text: '选项2'}
    ]
    
  • 修正状态同步逻辑
    所有对Select2选项列表、选中值的修改,操作完原生select节点后必须主动触发change事件同步组件内部状态:
    // 修改选中值后同步
    $('#target-select').val('2').trigger('change')
    // 追加新选项后同步
    $('#target-select').append(new Option('新选项', '3', false, false)).trigger('change')
    
    禁止直接操作Select2动态生成的下拉面板DOM,所有配置、数据修改都通过原生select节点或Select2官方API完成。
  • 解决层级/版本冲突
    若在Bootstrap Modal内使用Select2,初始化时显式指定dropdownParent为当前Modal节点,避免下拉面板被append到body导致的事件、数据绑定丢失:
    $('#target-select').select2({
      dropdownParent: $('#current-bootstrap-modal'),
      // 其余配置项
    })
    
    版本兼容问题优先升级Select2到4.0.13及以上稳定版,jQuery升级到3.x版本,不要使用第三方二次修改过的Select2压缩包。
  • 兜底兼容方案
    如果暂时无法定位具体丢数据的环节,可以在Select2加载完成后重写setClasses方法增加空值判断,从逻辑上跳过无效选项的处理:
    $.fn.select2.amd.require(['select2/results'], function (Results) {
      const originalSetClasses = Results.prototype.setClasses
      Results.prototype.setClasses = function () {
        const context = this
        this.data.current(function (selectedList) {
          const validSelectedIds = $.map(selectedList || [], function (item) {
            return item?.id ? item.id.toString() : ''
          })
          const $optionNodes = context.$results.find('.select2-results__option[aria-selected]')
          $optionNodes.each(function () {
            const $currentOpt = $(this)
            const optData = $.data(this, 'data')
            // 无有效绑定数据的选项直接跳过
            if (!optData || optData.id === undefined) return
            const currentId = optData.id.toString()
            const isSelected = (optData.element && optData.element.selected)
              || (!optData.element && $.inArray(currentId, validSelectedIds) > -1)
            $currentOpt.attr('aria-selected', isSelected ? 'true' : 'false')
          })
          const $activeNode = $optionNodes.filter('[aria-selected=true]')
          const $targetNode = $activeNode.length > 0 ? $activeNode.first() : $optionNodes.first()
          $targetNode.trigger('mouseenter')
        })
      }
    })
    

内容的提问来源于stack exchange,提问作者Tebby

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 15:39:14