将数据附加到 DOM
HTML5 引入了“数据”属性——可用于将数据附加到页面上的元素:
$('.foo').click(function(){alert($(this).data('id'))})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="foo" data-id="1" >Test</button>
通过 grouped_collection_select,您可以使用 html_options 参数将数据附加到元素。
获取选项
有几种方法可以解决这个问题:
js.erb
将 Rails 用作“懒人”SPA。这意味着您将对/entrees/1/sides.js 之类的内容发出 AJAX 请求。
class SidesController
def index
@entree = Entree.join(:sides).find(params[:entree_id])
@sides = @entree.sides
respond_to do |f|
f.html
f.js
end
end
end
这将呈现一个如下所示的模板:
// app/views/sides.js.erb
jQuery("#some_element").html('<%=j f.grouped_collection_select(:food_item, restaurant.categories, :entrees, :name, :id, :name) %>');
然而,这些 ruby、javascript 和 HTML 的混杂乱七八糟的东西,对我们在过去 10 年中所学到的关于构建应用程序的所有知识都是一团糟。
很难调试正在发生的事情 - 更糟糕的是,它无法使用 javascript 测试工具进行单元测试。您必须依赖硒或水豚,这非常缓慢。
客户端模板
在这种情况下,您会向服务器请求 JSON 并在客户端中对其进行转换:
假设/entrees/1/sides.json 返回一个对象数组:
[
{ id: 1, name: 'Mashed Potatoe' },
{ id: 22, name: 'Pickled Herring' },
{ id: 51, name: 'Grilled Veggies' }
]
您可以将其处理成一个选项元素列表,如下所示:
var promise = $.getJSON('/entrees/1/sides.json');
promise.pipe(function(data){
return $.map(data, function(item){
return $("<option>"+ item["name"] +"</option>").val(item[:id]);
});
}).done(function(opts){
$('#some_element').append(opts);
});
对于更复杂的示例,您将需要使用 JS 模板系统。
创建自定义分组选择
<%= content_tag :select, name: "meal[food_item]" id="meal_food_item">
<%= restaurant.categories.each do |c| %>
<% uri = category_sides_path(category_id: c, format: :json) %>
<%= content_tag(:optgroup, label: c.name, "data-uri" => uri) do %>
<%= options_from_collection_for_select(c.entrees, 'id', 'name') %>
<% end %>
<% end %>
<% end %>
并不是说uri 会出现在您可以获取侧面的任何地方。
$(".new_meal #meal_food_item").on('change', function() {
var $selected, promise, data_uri;
$selected = $(this).find(:selected).parents('optgroup');
promise = $.getJSON($selected.data('uri'));
promise.done(function(data){
// update the sides select
});
});