【问题标题】:Adding a value-dependent data attribute to a simple_form checkbox collection将依赖于值的数据属性添加到 simple_form 复选框集合
【发布时间】:2013-02-08 20:37:57
【问题描述】:

我正在为单个集合生成一个复选框列表,如下所示:

= f.input :parts, as:check_boxes, collection: @parts_list

我希望集合中的某些复选框消失/重新出现,具体取决于表单中较高选择小部件的值。 (例如从Robot select中选择“Tracker Robot”意味着“Legs”部分复选框消失,“Wheels”复选框出现等)

我想做的是将计算数据属性附加到每个单独的零件复选框,属性值列出可以使用该零件的机器人;然后一些 JS 将完成隐藏/显示复选框的工作。但是,我不知道如何使用 simple_form 生成这些数据属性。

我通常会创建一个自定义“部件”输入,但制作自定义集合输入似乎有问题;它会在 form_builder.rb 中查找一个命名方法 (collection_parts),但该方法不存在,如果我尝试扩展 FormBuilder,它会让我陷入一个主要的兔子洞。

我可以编写一些 JS 来将数据属性加载到生成的 HTML 中,但是我必须根据我的 Rails 数据生成自定义 JS,这感觉是错误的做法。

【问题讨论】:

    标签: ruby-on-rails forms simple-form custom-data-attribute


    【解决方案1】:

    假设表单用于Order 模型,并且您正在根据名为region 的字段的值更改parts 集合。

    更新表单视图。指定表单的 ID,region 字段和 parts 字段。

    = simple_form_for(@order, :html => { :id => "order-form"}) do |f|
      = f.input :region, :wrapper_html => { :id => "order-form-region",                      |
          "data-parts-url" => parts_orders_path(:id => @order.id, :region => @order.region)} |
    
      = f.input :parts, as: check_boxes, collection: @parts_list,                            |
          :wrapper_html => { id' => 'parts-check-box-list'}                                  |
    

    route.rb 文件中添加一个名为parts 的新操作。

    resources :orders do
      collection do
        get :parts
      end
    end
    

    将新动作添加到您的控制器

    class OrdersController < ApplicationController
    
      # expects id and region as parameters
      def parts
        @order =  params[:id].present? ? Order.find(params[:id]) : Order.new
        @parts_list = Part.where(:region => params[:region])
      end
    end
    

    添加助手

    def parts_collection(order, parts_list)
      "".tap do |pc| 
        # to generate the markup for collection we need a dummy form
        simple_form_for(order) do |f| 
          pc << f.input(:parts, as: check_boxes, collection: parts_list, 
            :wrapper_html => {:id => 'parts-check-box-list'})
        end
      end
    end
    

    为动作添加一个 js 视图 (orders/parts.js.erb)

    $('#parts-check-box-list').replaceWith('<%= j(parts_collection(@order, @parts_list)) %>');
    

    application.js 中为region 字段注册数据更改事件处理程序

    $(document).ready(function() {
      $('#order-form').on("change", "#order-form-region", function () {
        // Access the data-parts-url set in the region field to submit JS request
        $.getScript($(this).attr('data-parts-url'));
      });
    });
    

    【讨论】:

    • 首先,很抱歉延迟了一年半的回复!这是一个完整的答案,太好了。谢谢!最终,我选择了 Shuo Chen 的答案——尽管它不完整,但它表明我可以在不使用 AJAX 的情况下以非常简单的方式在页面中获取我需要的一切。但是对于比我的特殊情况更复杂的任何事情,你的看起来是一个很好的方法,我相信我将来会需要它。谢谢!
    【解决方案2】:

    我认为你可以这样做:

    = f.input :parts do
      = f.collection_check_boxes :parts, @parts_list, :id, :to_s, item_wrapper_tag: :label, item_wrapper_class: :checkbox do |b|
        - b.check_box(data: { YOUR DATA ATTRIBUTES HERE }) + b.text
    

    【讨论】:

    • 但是你怎么能动态地做到这一点呢?没有可绑定的变量……
    • b.object 是集合的单个元素,因此您可以执行 data: { identifier: b.object.identifier } 等操作,这将为组中的每个复选框提供自己的数据属性(如果将其放在 input_html 中,则与所有这些属性的相同值相反)
    • 首先,很抱歉延迟了一年半的回复!我最喜欢这个答案,因为它非常简单,即使还有额外的 Ruby 和 JS 代码要编写。我还没有测试过它(我早就离开了那个项目和雇主)但是 - 假设它有效 - 将每个部分的机器人列表放在数据元素中很有意义并且很容易动态比赛对阵。谢谢!
    【解决方案3】:

    这可能更简单。

    假设

    @robots - an array containing the list of robots
    @parts - a hash containing a list of parts for each robot
    

    示例代码

    # controller
    @robots = %w[tracker nontracker]
    @parts = { tracker: %w[wheels lcd resistor], nontracker: %w[lcd resistor] }
    
    # view
    = f.input :robots, as: :select, collection: @robots, input_html: { id: 'robot-select' }
    
    #parts-list
    
    :javascript
      var parts = #{@parts.to_json};
    
      $(document).ready(function() {
        $('#robot-select').change(function() {
          $('#parts-list').html('');
    
          $(parts[$(this).val()]).each(function(index, text) {
            $('#parts-list').append('<input type="checkbox" value=' + text + '>' + text + '</input>')
          })          
        })
      })
    

    如果你克隆 https://github.com/jvnill/simple_form_search_app 并转到 /robots,你可以看到这个工作

    【讨论】:

    • 首先,很抱歉延迟了一年半的回复!我喜欢这个代码是多么简单,它很小。我唯一不喜欢的是它在客户端构建了一大块表单,我仍然需要为复选框提供正确的部件名称。不过谢谢!
    【解决方案4】:

    SimpleForm 中的一些输入选项接受为集合中的每个项目调用的 lambda:

    f.input :role_ids, :collection => (1..10).to_a,
      :label_method => :to_i, :value_method => :to_i,
      :as => :check_boxes, :required=> true,
      :disabled => ->(item){ item.even? }
    

    input_html 似乎不是其中之一。

    解决方案可能是创建一个应用数据属性本身的自定义 SimpleForm 集合输入。也许没有那么灵活,但我认为这是目前唯一的方法。

    There's a tutorial page on GitHub 应该可以帮助您入门。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-17
      • 2013-02-07
      • 2016-06-07
      • 1970-01-01
      相关资源
      最近更新 更多