在Rails表单生成中,将输入框嵌套在f.label标签内

19

我想使用f.label方法创建表单元素标签,但是我想将表单元素嵌套在标签内部。这种做法可行吗?

-- 来自W3C --

为了隐式地将标签与另一个控件关联起来,控件元素必须位于LABEL元素的内容中。在这种情况下,LABEL只能包含一个控件元素。标签本身可以位于相关控件之前或之后。

在这个例子中,我们隐式地将两个标签与两个文本输入控件关联:

<form action="..." method="post">
 <p>
  <label>
     First Name
     <input type="text" name="firstname" />
  </label>
  <label>
     <input type="text" name="lastname" />
     Last Name
  </label>
  </p>
</form>
5个回答

24

你可以使用块将表单助手嵌套在标签内。这是一个使用HAML的示例,但它也适用于ERB。

= form_for your_resource do |f|
  = f.label :first_name do
    = f.text_field :first_name

2
适用于Rails 3(3.2.9),不需要HAML(纯erb)。 - Gavin Miller
谢谢!在Rails 4.0.4中,也不需要使用Haml。 - Subtletree

11

正如上面提到的丹·加兰德(Dan Garland)所说,您可以通过一个简单的代码块在标签内嵌套输入框。我提供这个答案作为示例,使用ERB并特别说明如何使Bootstrap按钮组像单选按钮一样工作,因为它们需要这种嵌套。我花了一些时间才搞清楚,希望能帮助其他人。

对于这个例子(Rails 4.2),按钮组让用户在3个不同的距离选项之间进行选择:

<%= form_for(@location) do |f| %>
  <div class="field form-group">
    <%= f.label :distance %><br>
    <div class="btn-group" data-toggle="buttons">
      <%= f.label :distance, class: "btn btn-primary active" do %>
        <%= f.radio_button :distance, 0.3, checked: true %>
        0.3 miles
      <% end %>
      <%= f.label :distance, class: "btn btn-primary" do %>
        <%= f.radio_button :distance, 0.5 %>
        0.5 miles
      <% end %>
      <%= f.label :distance, class: "btn btn-primary" do %>
        <%= f.radio_button :distance, 1 %>
        1 mile
      <% end %>
    </div>
  </div>
  <div class="actions">
    <%= f.submit "Submit Location", class: "btn btn-success" %>
  </div>
<% end %>

附注:我目前还无法发布屏幕截图以展示其外观,但是一旦我获得足够的声望点,我会这样做。


8
您可以使用自定义的FormBuilder来允许标签助手接受块。操作很简单,只需如下所示:
class SmartLabelFormBuilder < ActionView::Helpers::FormBuilder
  def label(method, content_or_options_with_block = nil, options = {}, &block)
    if !block_given?
      super(method, content_or_options_with_block, options)
    else
      options = content_or_options_with_block.is_a?(Hash) ? content_or_options_with_block.stringify_keys : {}

      @template.content_tag(:label, options, &block)
    end
  end
end

然后,您可以像这样使用表单生成器:
<% form_for(@article, :builder => SmartLabelFormBuilder) do |form| %>
  <% form.label(:title) do %>
    Title
    <%= form.text_field(:title) %>
  <% end %>
<% end %>

包装得很好,但它没有输出正常助手所做的“for”属性。也就是说,当我说“<%form.label(:title)%>”时,它会输出“<label for =”title“>”,但当我添加块时,无论我做什么,它都只输出“<label>”。我做错了什么吗? - Ben Saufley
2
@BenSaufley:当标签包裹输入元素时,for属性不是必需的。http://www.w3.org/TR/html401/interact/forms.html#h-17.9.1 - rogerkk

2
使用这个小技巧
<%= f.label(:content, "#{f.check_box(:allow_posts)}\n#{:content}\n".html_safe, :class => "checkbox") %>

将会给你这个

<label class="checkbox" for="pages_content"><input name="pages[allow_posts]" type="hidden" value="0"><input id="pages_allow_posts" name="pages[allow_posts]" type="checkbox" value="1">

content


抱歉,我以为这是关于复选框被包装在标签标记中的问题。 - Moshe

1

使用内置的Rails labellabel_tag助手无法实现此功能,因为它们不接受块。但是,如果您想要嵌套,那么为什么不直接使用HTML元素呢?—

<label>
  <%= f.text_field :firstname %>
</label>

仅仅是因为我想利用Rails标签的自动化功能。 - Michael
Rails的helper将输入元素ID属性的值分配给标签元素的“for”属性。它并不特别复杂。无论您使用Rails的helper还是将输入元素嵌套在标签内,效果都是相同的;在浏览器中单击标签会将焦点设置到输入元素。 - John Topley
这让我觉得Rails中存在一个巨大的疏忽,我真的很惊讶这个问题还没有得到解决。至少我们有像Tim Riley这样的人来帮助我们解决问题。 - fisherwebdev
我正在使用较旧版本的Rails。这对我很有用,因为有时“helpers”会妨碍你,而编写所需的HTML比试图强迫Rails让你做你想做的事情更容易。 - Phil DD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接