【发布时间】:2021-09-17 07:43:33
【问题描述】:
在由 Rails 6.1 控制的网站表单上,我想实现“动态”或级联下拉菜单,以便第二个下拉菜单中的选项根据第一个下拉菜单中的所选项目而有所不同。
具体来说,我有一个与Country 和Town 模型相关联的Person 模型。关系是Personbelongs_to 和Town,其中belongs_to 和Country 在has_many 中。定义了方法Country#name 和Town#name。在create 和Person 的网站上的新 表单中,用户首先从下拉菜单(选择框)中选择国家,然后选择城镇 在第二个下拉菜单中。
我基本上遵循了#88 Dynamic Select Menus (revised) 的过程,但在标准 jQuery 中重写了它,而不是在 Railcasts 中使用 Coffee。
简而言之,我使用 Rail 的 form.grouped_collection_select 辅助方法为城镇创建了一个选择框;生成的 HTML 中的部分包含许多OPTGROUP,每个都对应一个国家,其中有多个子城镇belongs_to。关联的 jQuery 脚本过滤第二个(即,Town)下拉菜单,将 Country 下拉菜单中的选定项目与每个 OPTGROUP 的 LABEL 进行比较城镇下拉菜单(选择框)。
它有点工作,但有一个严重的缺陷。基本上,它在第一次点击时起作用。然而,一旦用户改变主意并重新选择不同的国家,城镇的所有选项都会消失。换句话说,用户的第一选择是不可逆的。这是一个糟糕的界面。
如何解决这个问题,让用户的选择总是可逆的?
下面是表单视图(hrb.erb)和Javascript jQuery代码中的相关部分。这里,person 是模型Person 的一个新实例。它使用 Rails 6.1.4、Ruby 3.0.1 和 jQuery 3.5.1 进行了测试。
erb.html 用于表单:
<%= form_with(model: person, local: true) do |form| %>
<div class="field">
<%= form.label 'town_id.country_id', 'Country'%>
<%= form.collection_select town_id.country_id', Country.all,
:id, :name, include_blank: true %>
</div>
<div class="field">
<%= form.label 'place.town_id' %>
<%= form.grouped_collection_select 'place.town_id', Country.all,
:towns, :name, :id, :name, include_blank: true %>
</div>
<% end %>
Javascript jQuery:
var contsel = "#"+$.escapeSelector('person_place.town_id.country_id');
$(contsel).change(function(){
var prefsel = "#"+$.escapeSelector('person_place.town_id');
var contsel = "#"+$.escapeSelector('person_place.town_id.country_id');
var country = $.escapeSelector($(contsel+' :selected').text());
var towns = $(prefsel).html();
var options = $(towns).filter("optgroup[label='"+country+"']").html();
if (options) {
$(prefsel).html(options);
} else {
$(prefsel).empty();
}
})
【问题讨论】:
标签: javascript jquery ruby-on-rails forms drop-down-menu