Rails表单根据下拉选项值动态隐藏对应区块的实现方法
Rails Slim 表单下拉选项联动显隐实现
实现这个效果不需要改动后端逻辑,只需要两步:先给需要联动控制的表单项加专属标识,再写少量前端JS监听下拉选择事件、控制对应区块显隐即可,同时要处理页面初始加载的默认状态,避免编辑/刷新页面时显示错乱。
第一步:修改Slim表单代码,给联动区块加标识
给两个触发联动的下拉框加固定ID方便JS获取,给需要被控制显隐的表单项分组加专属逻辑类(推荐用js-前缀区分样式类和JS绑定类,避免后续改样式误碰逻辑),修正原代码的缩进问题后代码如下:
= form_with(model: @room, local: true, html: {multipart: true}) do |f| - if @room && @room.errors.any? #error_explanation %h2= "#{pluralize(@room.errors.count, "error")} prohibited this room from being saved:" %ul - @room.errors.full_messages.each do |message| %li= message .form-group.mb-3 = f.select :cat_route, [ "channel", "chat", "bot", "service"], {}, class: 'form-control', id: 'cat-route-select' / services字段区块,受route下拉控制 .form-group.mb-3.js-services-field = f.select :services, ["option1", "option2", "option3"], {}, class: 'form-control' .form-group.mb-3 = f.select :route, ["Buy", "Sell"], {}, class: 'form-control', id: 'route-select' / 以下为chat场景需要隐藏的非核心字段,统一加控制类 .form-group.mb-3.js-non-chat-field = f.select :city, ["City1", "City2", "City3"], {}, class: 'form-control' .form-group.mb-3 = f.text_field :name, placeholder: "name", class: 'form-control' .form-group.mb-3 = f.text_field :link, placeholder: "link", class: 'form-control' .form-group.mb-3.js-non-chat-field = f.select :category, ["SMM", "IT", "Gif Video"], {}, class: 'form-control' .form-group.mb-3 = f.text_field :content, class: 'form-control' .form-group.mb-3.js-non-chat-field = f.text_field :price, class: 'form-control' .form-group.mb-3.js-non-chat-field = f.label 'Image' = f.file_field :image, class: 'form-control' .form-group.mb-3.js-non-chat-field = f.check_box :free, id: 'free', class: 'form-check-input' = f.label :option, 'Free', class: 'form-check-label', for: 'free' .form-group.mb-3.js-non-chat-field = f.check_box :hot, id: 'hot', class: 'form-check-input' = f.label 'hot', class: 'form-check-label small', for: 'hot' %br .actions = f.submit 'Create', class: 'btn btn-outline-primary btn-block'
注:上述代码默认将
name、link、content作为所有场景都保留的核心字段,如果你需要调整chat场景保留的字段,只要给对应区块加/删js-non-chat-field类即可。
第二步:添加联动JS逻辑
把下面这段代码放到对应页面模板的尾部,或者放到项目的JS入口文件中即可,无额外依赖,兼容所有现代浏览器:
document.addEventListener('DOMContentLoaded', function() { // 获取DOM元素 const routeSelect = document.getElementById('route-select') const catRouteSelect = document.getElementById('cat-route-select') const serviceFields = document.querySelectorAll('.js-services-field') const nonChatFields = document.querySelectorAll('.js-non-chat-field') // route下拉联动逻辑:选中Buy时隐藏services字段 function syncRouteFields() { const isBuySelected = routeSelect.value === 'Buy' serviceFields.forEach(field => { field.style.display = isBuySelected ? 'none' : 'block' // 如果需要禁止隐藏字段提交参数,可以打开下面这行注释 // field.querySelector('select, input').disabled = isBuySelected }) } // cat_route下拉联动逻辑:选中chat时隐藏非核心字段 function syncCatRouteFields() { const isChatSelected = catRouteSelect.value === 'chat' nonChatFields.forEach(field => { field.style.display = isChatSelected ? 'none' : 'block' // 同理需要禁止提交的话打开下面注释 // field.querySelector('select, input').disabled = isChatSelected }) } // 绑定下拉选择事件 routeSelect.addEventListener('change', syncRouteFields) catRouteSelect.addEventListener('change', syncCatRouteFields) // 页面初始化时执行一次,适配编辑页默认值、刷新后默认选中的状态 syncRouteFields() syncCatRouteFields() })
补充说明
- 如果你的项目已经引入jQuery,可以把原生JS换成jQuery写法,逻辑完全一致,代码会更简短。
- 如果需要做显隐的过渡动画,可以把直接修改
display的逻辑换成加/删CSS类,配合CSS transition实现即可。 - 建议加上
disabled属性控制,避免用户切换选项后隐藏字段的旧值被提交到后端,造成数据异常。
内容的提问来源于stack exchange,提问作者Andrew Kancev
相关产品推荐
相关产品推荐

