【问题标题】:How do you get the Ruby on Rails generated id of a form element for reference in JavaScript?如何获取 Ruby on Rails 生成的表单元素 id 以供 JavaScript 参考?
【发布时间】:2011-06-16 17:20:57
【问题描述】:

当使用form_for 帮助器和text_field 调用时,Ruby on Rails 将为它输出的<input /> 元素生成一个唯一的ID。如何生成相同的 id 以供以后包含到稍后生成的 JavaScript 中?

<%= form_for @user do |f| %>
  <%= f.text_field :username %>
<% end %>

然后在页面后面:

<%= javascript_tag do %>
  $('<%= id of the :username field %>').doSomethingReallyCool();
<% end %>

【问题讨论】:

  • 我想指出,赏金中的附加示例只是答案有用的另一个特殊情况。这不是一个不同的问题。为了被接受,答案应该足够通用,以适合原始示例和我的示例。这两个示例都展示了一个需要“获取 Ruby on Rails 生成的表单元素的 id 以在 JavaScript 中引用”的情况。
  • 关于当前赏金的元问题meta.stackoverflow.com/q/351561/73226
  • @ClaudioFloreani 不,那不行。请记住,在赏金到期或被授予后,您的赏金文本将不再可见。在赏金消失后,解决赏金问题的答案将毫无意义。请提出一个新问题。
  • @duskwuff 我认为您在制作 cmets 时并不了解这两个示例都是相同一般情况的两个特殊情况。作者只举了一个“Ruby on Rails 生成表单元素的 id”的例子,我再举一个例子。示例 A 和示例 B。但问题是“如何获取 Ruby on Rails 生成的表单元素的 id 以供 JavaScript 参考?”它仍然缺乏一个像样的答案。当前接受的答案(“创建自定义表单构建器”)现在被认为是不好的做法。
  • id 不是 name-of-model_name-of-the-attribute 吗?你不能不给它一个 id 我在 html 选项中指定它吗?

标签: javascript ruby-on-rails forms


【解决方案1】:

您需要自己指定 id。这里从表单的 object_id 生成 id 可以保证在嵌套表单的情况下它不会与 username 的另一个 text_field 冲突。

<%= form_for @user do |f| %>
  <%- id = "username_#{f.object_id}" %>
  <%= f.text_field :username, :id=>id %>
<% end %>

<%= javascript_tag do %>
  $("##{id}").doSomethingReallyCool();
<% end %>

【讨论】:

  • 在这种情况下这不是一个真正的选项,因为 JavaScript 和表单字段是动态的,我不一定有能力控制 f.text_field 调用。
  • 这对于特定情况下的 id 不是由 Rails 应用程序动态生成的明显答案。
【解决方案2】:

我最终创建了一个自定义表单构建器来直接公开属性

class FormBuilder < ActionView::Helpers::FormBuilder
  def id_for(method, options={})
   InstanceTag.new( object_name, method, self, object ) \
               .id_for( options )               
  end
end

class InstanceTag < ActionView::Helpers::InstanceTag
  def id_for( options )
    add_default_name_and_id(options)
    options['id']
  end
end

然后设置默认的表单生成器

ActionView::Base.default_form_builder = FormBuilder 

【讨论】:

  • 很好,谢谢!将它放入 Rails 应用程序的最佳位置在哪里?
  • Mike:一个 config/initializers/{file_name}.rb 文件就可以了
  • 我在概念化如何调用它时遇到了麻烦。对我的大脑来说太元了,我想。能举个简单的例子吗?
  • 在 Rails 5 中,ActionView::Helpers::InstanceTag 应替换为 ActionView::Helpers::Tags::Base,InstanceTag.new(object_name, method, self, object) 应替换为 InstanceTag.new(object_name, method, self, options)。
【解决方案3】:

我不太喜欢我自己的解决方案,但我尽量不去修补 InstanceTag。

不幸的是,这意味着要从 ActionView::Helpers::InstanceTagMethods 中取消清理代码

class MyCoolFormBuilder < ActionView::Helpers::FormBuilder
    def sanitized_object_name
      @sanitized_object_name ||= object_name.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").sub(/_$/, "")
    end

    def field_id_for(method)
      "#{sanitized_object_name}_#{method.to_s.sub(/\?$/,"")}"
    end
end

【讨论】:

    【解决方案4】:

    查看表单构建器选项:

    <%= form_for @user do |f| %>
      <% form_css_id = "#" + f.options[:html][:id] %>
    <% end %>
    

    Options 至少应包含以下数据:css 类、id、http 方法和真实性令牌。

    【讨论】:

    • f.options[:html] 对我来说是零。
    • 对我来说不是零!我希望我能更多地支持这一点。这对于 HTML5 的新“form”属性特别有用。试试这个:&lt;% f.submit "Save Changes", form: f.options[:html][:id] %&gt;。现在您可以使用 javascript 将该表单移动到您想要的任何位置,并且仍然可以提交表单。太好了!
    • 嵌套对象似乎为零,但在父窗体上它工作正常。
    • 要清楚,OP询问如何获取用户名字段的ID,而不是表单ID。这将返回表单 ID。
    【解决方案5】:

    如果有人拥有来自fields_for 块的FormBuilder 对象,则可以使用此sn-p 获取其id:

    <%= form.fields_for :something do |fields_form| %>
      <%= fields_form.object_name.gsub(/[\[\]]+/, '_').chop %>id
    <% end %>
    

    FieldsForm#object_name 返回字段的 ID,如下所示:user[address][0]。接下来,正则表达式替换将一个或多个括号组更改为下划线。此替换会留下一个尾随下划线,并在其后附加字母 id。对于之前提供的示例,这将导致 user_address_0_id。

    【讨论】:

    • 我正在尝试您添加的 sn-p。是吗? &lt;%= fields_form.object_name.gsub(/[\[\]]+/, '_').chop %&gt;_id
    【解决方案6】:

    由于您的 Javascript 代码放置在 ruby​​ 嵌入文件 (.erb) 中,该文件在发送到客户端浏览器之前由服务器解释,您可以使用 ruby​​ sn-p 生成所需的 JS 变量,例如:

    var id='#id_for_'+<%= @user.username %>
    var id='#comment_info_'+<%= n %>
    

    然后将其简单地用作$(id).doSomethingReallyCool();。

    如果您需要在第一个实例中控制表单生成的 id 的值,您可以在 html 哈希选项中传递 id:

    f.text_field :username, id:"id_for_#{…}"
    

    如果您使用不显眼的 JS 方法,您希望将 JS 代码放入部分 (.js.erb) 中,如果用户客户端允许 JS,则让控制器使用它。例如:

    class FooController < ApplicationController
    
    def foo_doo
      … # some logic
      respond_to do |format|
        format.js # this will render javascript in file “foo_doo.js.erb” if allowed
        format.html { … } # html fallback for unobtrusive javascript
      end
    end
    

    这是当今推荐的方法。现在的问题是您需要将变量传递给您的 JS 代码。如果这些变量来自表单,请将它们放置在适当的隐藏表单字段中。然后使用渲染器的 locals 选项让您的部分可用,如:

    format.js { render 'foo_doo', locals: {n:n} }
    

    如果 JS 代码正在更新使用某些变量的模板,请使用相同的方法:

    var id='#comment_info_'+<%= n %>
    $(id).replaceWith("<%= j (render partial:…, locals: {…}) %>")
    

    【讨论】:

      【解决方案7】:

      我假设页面中有多个form_for,每个都有自己的提交按钮。我想我会这样做:

      在 form_for 中有一个隐藏字段,并将其值设置为输入字段的 id。在这里,我选择了input_#{n} 作为输入字段的 id。当然,我会为每个输入定义 id。

      <%= form_for @user do |f| %>
        <%= f.text_field :username, id: "input_#{n}" %>
        <%= hidden_field_tag 'user[input_id]', value: "input_#{n}" %>
        <%= f.submit %>
      <% end %>   
      

      然后在提交时,我可以在我的参数params[:user][:input_id] 中获取表单输入的 id,我可以使用locals 将其传递给js.erb。

      希望这会有所帮助:)

      【讨论】:

        【解决方案8】:

        在 Rails 4.1 中,我可以通过以下方式获取 id:

        ActionView::Base::Tags::Base.new(
          f.object_name,
          :username,
          :this_param_is_ignored,
        ).send(:tag_id)
        

        它适用于嵌套表单 (fields_for)。

        【讨论】:

        • 在 Rails 6.1.* 中像魅力一样工作,谢谢!
        猜你喜欢
        • 1970-01-01
        • 2014-09-22
        • 1970-01-01
        • 2020-02-11
        • 1970-01-01
        • 2017-05-26
        • 1970-01-01
        • 1970-01-01
        • 2021-12-05
        相关资源
        最近更新 更多