在 Rails 中使用不显眼的 javascript 的父子选择下拉关系

Parent-child select dropdown relationships using unobtrusive javascript in Rails

提问人:FuzzyJulz 提问时间:6/18/2014 最后编辑:FuzzyJulz 更新时间:9/9/2014 访问量:995

问:

我有一个应用程序,它在场馆和大厅之间有一个非常简单的父>子关系(所以一个活动有一个场地,一个场地有很多大厅),在管理屏幕中,我希望能够选择一个场地(通过选择框中的关联)并让它自动填充(最好是 AJAX JSON 请求)该场地的大厅(在另一个选择框中)。

在我看来,这种东西要么是标准的,要么是在某个地方的宝石中,有没有更好的选择?

我已经附上了我当前的解决方案

jquery ruby-on-rails html-select 简单形式 unobtrusive-javascript

评论


答:

-1赞 FuzzyJulz 6/18/2014 #1

我仔细研究了一下,发现: 如何使用不显眼的jQuery脚本在Rails 4中实现依赖下拉列表

我已经接受了这个并对其进行了一点混蛋,以使其正常工作并使其更简单,并纠正了一些错误:chosen

_form.haml:

= simple_form_for(@event, ... ) do |f|
  = f.association :hall, collection: @event.venue.halls.order(:name), include_blank: false, input_html: {class: "chosen", 
    data: {linked: "select", 
           linked_parent_id: "event_venue_id",
           linked_collection_path: venue_halls_path(":venue_id:")}}
  = f.association :venue, include_blank: false , :input_html => {class: "chosen"}

请注意,value 和 label 是可选的,以下方法也有效:

    data: {linked: "select", 
           linked_parent_id: "event_venue_id",
           linked_collection_path: venue_halls_path(":venue_id:"),
           linked_collection_value: "id",
           linked_collection_label: "name"}

routes.rb 包含以下映射(通过资源):

venue_halls_path     GET     /venues/:venue_id/halls(.:format)   halls#index

...
resources :venues, shallow: true do
  resources :halls
end
...

halls_controller.rb:

...
def index
  @halls = Venue.find(params[:venue_id]).halls.order(:name)
  respond_to do |format|
    format.html {}
    format.json { render json: @halls.to_json }
  end
end
...

应用程序.js:

...
$('select[data-linked=select]').each(function (i) {
  var child_dom_id = $(this).attr('id');
  var parent_dom_id = $(this).data('linked-parent-id');
  var path_mask = $(this).data('linked-collection-path');
  var path_regexp = /:[0-9a-zA-Z_]+:/g;
  var option_value = $(this).data('linked-collection-value');
  var option_label = $(this).data('linked-collection-label');
  var child = $('select#' + child_dom_id);
  var parent = $('#' + parent_dom_id);
  var loading_prompt = $('<option value=\"\">').text('Loading options...');
  var no_items_prompt = $('<option value=\"\">').text('No options available');

  option_value = (option_value === undefined ? "id" : option_value);
  option_label = (option_label === undefined ? "name" : option_label);

  parent.on('change', function () {
    child.attr('disabled', true);
    child.empty().append(loading_prompt);
    child.trigger("chosen:updated")
    if (parent.val()) {
      var path = path_mask.replace(path_regexp, parent.val());
      $.getJSON(path, function (data) {
        child.empty();
        var itemsChanged = false;
        $.each(data, function (i, object) {
          if (object[option_value] === undefined) {
            $.each(object, function (i, subobject) {
              child.append($('<option>').attr('value', subobject[option_value]).text(subobject[option_label]));
              itemsChanged = true;
            });
          } else {
            child.append($('<option>').attr('value', object[option_value]).text(object[option_label]));
            itemsChanged = true;
          }
        });
        child.attr('disabled', !itemsChanged);
        if (!itemsChanged) {
          child.append(no_items_prompt);
        }
        child.trigger("chosen:updated")
      });
    }
  });
});