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

如何在tom-select动态加载选项后为表单下拉框回显值?

解决方案

针对Tom Select + Stimulus动态加载选项时的表单回显问题,这里有几个实用的优雅方案:

方案1:利用Stimulus生命周期+Data属性延迟设置值

后端渲染表单时,把Session中存储的选中值挂载到下拉框的data属性上,然后在Stimulus控制器中,等Tom Select初始化完成后再读取该值并设置选中状态。

后端渲染HTML示例

<select data-controller="tom-select" data-tom-select-target-value="<%= session[:selected_category_id] %>">
  <!-- 初始为空,由Stimulus动态加载选项 -->
</select>

Stimulus控制器代码

import { Controller } from "@hotwired/stimulus"
import TomSelect from "tom-select"

export default class extends Controller {
  connect() {
    // 初始化Tom Select
    this.tomSelect = new TomSelect(this.element, {
      // 你的Tom Select配置,比如远程加载选项
      valueField: 'id',
      labelField: 'name',
      searchField: 'name',
      load: (query, callback) => {
        fetch(`/api/categories?q=${query}`)
          .then(response => response.json())
          .then(data => callback(data))
          .catch(() => callback([]))
      }
    })

    // 初始化完成后,检查并设置回显值
    const targetValue = this.element.dataset.tomSelectTargetValue
    if (targetValue) {
      // 先判断选项是否已存在,不存在则先添加再选中
      if (!this.tomSelect.options[targetValue]) {
        // 如果需要,可以先通过API获取该选项的详细信息再添加
        fetch(`/api/categories/${targetValue}`)
          .then(res => res.json())
          .then(item => {
            this.tomSelect.addItem(item.id)
          })
      } else {
        this.tomSelect.setValue(targetValue)
      }
    }
  }

  disconnect() {
    // 清理Tom Select实例,避免内存泄漏
    if (this.tomSelect) {
      this.tomSelect.destroy()
    }
  }
}

方案2:预渲染隐藏的目标选项

直接在HTML中渲染对应Session值的隐藏option,Tom Select初始化时会自动识别并选中该选项,后续动态加载的其他选项不会覆盖这个选中状态。

后端渲染HTML示例

<select data-controller="tom-select">
  <% if session[:selected_category_id].present? %>
    <!-- 预渲染目标选项,设置为隐藏避免初始显示 -->
    <option value="<%= session[:selected_category_id] %>" hidden><%= session[:selected_category_name] %></option>
  <% end %>
</select>

Stimulus控制器代码

import { Controller } from "@hotwired/stimulus"
import TomSelect from "tom-select"

export default class extends Controller {
  connect() {
    this.tomSelect = new TomSelect(this.element, {
      // 你的Tom Select配置,动态加载其他选项
      load: (query, callback) => {
        fetch(`/api/categories?q=${query}`)
          .then(response => response.json())
          .then(data => callback(data))
          .catch(() => callback([]))
      }
    })
    // 无需额外设置值,Tom Select会自动选中预渲染的option
  }

  disconnect() {
    if (this.tomSelect) {
      this.tomSelect.destroy()
    }
  }
}

方案3:监听Tom Select的load完成事件(针对异步加载选项场景)

如果选项是通过异步请求加载的,可以在Tom Select的load回调完成后,再设置回显值,确保选项池已包含目标值(或主动添加)。

Stimulus控制器代码

import { Controller } from "@hotwired/stimulus"
import TomSelect from "tom-select"

export default class extends Controller {
  connect() {
    const targetValue = this.element.dataset.tomSelectTargetValue
    this.tomSelect = new TomSelect(this.element, {
      valueField: 'id',
      labelField: 'name',
      searchField: 'name',
      load: (query, callback) => {
        fetch(`/api/categories?q=${query}`)
          .then(response => response.json())
          .then(data => {
            callback(data)
            // 加载完成后检查并设置回显值
            if (targetValue) {
              // 检查选项是否存在,不存在则添加
              if (!this.tomSelect.options[targetValue]) {
                fetch(`/api/categories/${targetValue}`)
                  .then(res => res.json())
                  .then(item => {
                    this.tomSelect.addItem(item.id)
                  })
              } else {
                this.tomSelect.setValue(targetValue)
              }
            }
          })
          .catch(() => callback([]))
      }
    })
  }

  disconnect() {
    if (this.tomSelect) {
      this.tomSelect.destroy()
    }
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 20:39:19