【问题标题】:How to dynamically show/hide Rails form fields using CoffeeScript and JQuery?如何使用 CoffeeScript 和 JQuery 动态显示/隐藏 Rails 表单字段?
【发布时间】:2014-01-19 08:47:06
【问题描述】:

尝试构建一个基于用户选择的值提交给多个模型的表单。

我认为“#196:嵌套模型表单”(http://railscasts.com/episodes/196-nested-model-form-revised) 的 Railscast 插曲会有所帮助,但解决方案并不是我想要的。我创建了多个模型,它们之间有关联(belongs_tohas_many),并包含 accepts_nested_attributes_for 声明以支持表单将生成的对象: p>

class User < ActiveRecord::Base
  attr_accessible :password_digest, :uname, :user_type, :artist_attributes, :sponsor_attributes
  has_many :artists
  has_many :sponsors
  accepts_nested_attributes_for :artists, :sponsors

  validates :uname, presence: true, uniqueness: true
  has_secure_password
end

class Artist < ActiveRecord::Base
  attr_accessible :user_id, :address, :email, :genre, :name, :phone, :photo, :preferences, :rate, :terms, :artist_type
  belongs_to :user

  validates :email, :genre, :name, :phone, :photo, :preferences, :pwd, :terms, :artist_type, :uname, presence: true
  validates :rate, numericality: {greater_than_or_equal_to: 0}
  validates :phone, numericality: true  
  validates_length_of :phone, :minimum => 10, :message => "Phone numbers need to be at least 10 digits"
  validates :email, uniqueness: true
end

class Sponsor < ActiveRecord::Base
  attr_accessible :user_id, :address, :email, :name, :phone
  has_many :venues
  belongs_to :user

  validates :email, :name, :phone, presence: true
  validates :email, uniqueness: true
  validates :phone, numericality: true
  validates_length_of :phone, :minimum => 10, :message => "Phone numbers need to be at least 10 digits"
end

我使用 form_for 映射到 User 模型,并使用 fields_for 映射到部分用户表单中的 Sponsor 和 Artist 模型(在 Users#new 中呈现查看):

<%= form_for(@user) do |f| %>
  # Error handling omitted 
  <div class="field">
    <%= f.label :uname, "User Name" %><br />
    <%= f.text_field :uname %>
  </div>
  <div class="field">
    <%= f.label :pwd, "Password" %><br />
    <%= f.password_field :pwd, size: 30 %>
  </div>
  <div class="field">
    <%= f.label :pwd, "Confirm Password" %><br />
    <%= f.password_field :pwd, size: 30 %>
  </div>

  <!-- Want to use these radio buttons to dynamically display/hide the fields for the Sponsor and Artist models -->
  <div class="field">
    <%= f.label :user_type, "Register as: " %><br />
    <%= f.radio_button :user_type, "Sponsor", class: "sponsor_fields" %><%= f.label :user_type, "Sponsor", value: "Sponsor" %>
    <%= f.radio_button :user_type, "Artist", class: "artist_fields" %><%= f.label :user_type, "Artist", value: "Artist" %>
  </div>
  <!-- End dynamic display radio buttons --> 

  <div id="sponsor_fields" style="display:none;">
    <% f.fields_for :sponsor do |s| %>
    <div class="field">
      <%= s.label :name %><br />
      <%= s.text_field :name %>
    </div>
    <div class="field">
      <%= s.label :email %><br />
      <%= s.text_field :email %>
    </div>
    <div class="field">
      <%= s.label :phone %><br />
      <%= s.text_field :phone %>
    </div>
    <div class="field">
      <%= s.label :address %><br />
      <%= s.text_area :address %>
    </div>
    <% end %>
  </div>
  <div id="artist_fields" style="display:none;">
    <% f.fields_for :artist do |a| %>
    <div class="field">
      <%= a.label :name %><br />
      <%= a.text_field :name %>
    </div>
    <div class="field">
      <%= a.label :email %><br />
      <%= a.text_field :email %>
    </div>
    <div class="field">
      <%= a.label :phone %><br />
      <%= a.text_field :phone %>
    </div>
    <div class="field">
      <%= a.label :address %><br />
      <%= a.text_area :address %>
    </div>
    <div class="field">
      <%= a.label :artist_type %><br />
      <%= a.text_field :artist_type %>
    </div>
    <div class="field">
      <%= a.label :rate %><br />
      <%= a.number_field :rate %>
    </div>
    <div class="field">
      <%= a.label :terms %><br />
      <%= a.text_field :terms %>
    </div>
    <div class="field">
      <%= a.label :genre %><br />
      <%= a.text_area :genre %>
    </div>
    <div class="field">
      <%= a.label :preferences %><br />
      <%= a.text_area :preferences %>
    </div>
    <div class="field">
      <%= a.label :photo %><br />
      <%= a.text_field :photo %>
    </div>
  <% end %>
  </div>

  <div class="actions">
  <%= f.submit %>
  </div>
<% end %>

这是我试图用来显示带有 ID 属性的 &lt;DIV&gt; 块的 Coffeescript 和 Jquery 代码(注意:我不是 Jquery 专家,所以我确信这种语法存在重大问题)包含单选按钮元素的值:

jQuery ->
    $('form').on 'change', 'input[name=user_type]', (event) ->
        curr = $(this).value.toLowerCase()
        alt = $(this).closest('input[name=user_type]').value.toLowerCase()
        $('#'+ alt +'_fields').hide()
        $('#'+ curr +'_fields').show()

当我单击单选按钮时,没有任何反应。我认为它可能与每个&lt;DIV&gt; 中的display:none 属性有关,所以我删除了它们并意识到 fields_for 表单元素根本没有显示。

两个 fields_for 块可以包含在同一个表单中吗?应该如何编码以使表单元素显示?我希望 Sponsor 和 Artist 表单元素默认隐藏,但在单击相应的单选按钮时显示。

我是 Ruby on Rails、Jquery 和 Coffeescript 的新手,因此非常感谢任何帮助。仅供参考:我使用 Railsinstaller(Ruby 版本 1.9.3)安装了 Rails 3.2.13,并验证了 Coffeescript 版本 1.6.3 已安装。有什么想法吗?

更新Bartosz 的帮助下找到了问题(谢谢)。我查看了浏览器中呈现的 HTML 的源代码,发现 jQuery 选择器中使用的 name 属性的值不正确。而不是$('input[name=user_type]'),选择器应该包含控制器名称$('input[name="user[user_type]"]')。我修改了 Bartosz 更简洁的 Coffeescript 代码,以使用正确命名的选择器实现所需的显示/隐藏功能:

jQuery ->
    $('input[name="user[user_type]"]').on 'click', (event) ->
        curr = event.target.value.toLowerCase()
        $('[id$=_fields]').hide()
        $('#'+curr+'_fields').show()

希望这可以帮助其他人像我一样寻找答案......

【问题讨论】:

  • 最简单的方法是使用 gem coocon github.com/nathanvda/cocoon 它实现你想要的所有东西。
  • 不,“jQuery ->”行下的所有内容也应该缩进。我会在原帖中解决这个问题...

标签: jquery ruby-on-rails coffeescript


【解决方案1】:

回调是否被触发了?

试试这个:

$('input[name=user_type]').change (e) ->
    curr = e.target.value.toLowerCase()
    $('[id$=_fields]').hide()
    $('#'+ curr +'_fields').show()

【讨论】:

  • 感谢建议的 Coffeescript 语法,Bartosz(更简洁,你用选择器通配符教会了我一些新东西)。我用您建议的代码替换了我 users.js.coffee 文件中jQuery -&gt; 行之后的代码,但它仍然不起作用。看起来回调没有被触发。
  • 尝试使用断点或console.log(e) 进行一些调试。检查输入是否存在console.log $('input[name=user_type]')。我不明白为什么这不起作用。
  • 我直接在 \app\views\users_form.html.erb 中添加了一个脚本块,看看是否会有所作为,但它也不起作用(不是甚至警报): $(document).ready(function(){ $('input[name=user_type]').click(function(){alert(this.value); $('[id$=_fields] ').hide(); $('#'+ this.value.toLowerCase() +'_fields').show(); }); });
  • 抱歉这个菜鸟问题,但我应该在哪里插入console.log(e) 电话?在咖啡脚本中?
  • change (e) -&gt; 功能块内。但我想如果警报没有显示,它什么也不会显示。检查 JS 控制台是否有错误或向我们展示 repo。
猜你喜欢
  • 1970-01-01
  • 2013-02-14
  • 2013-07-23
  • 2012-03-11
  • 1970-01-01
  • 2018-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多