【问题标题】:Passing variable value form js function to rails view (dynamic select)将变量值从js函数传递到rails视图(动态选择)
【发布时间】:2011-04-27 10:41:27
【问题描述】:

我使用Ryan's method 使用jQuery 通过JavaScript 动态添加和删除嵌套模型字段。

有4个模型:client、c_person;项目,p_person。以及一对多的关联:client 有很多 c_people,project 有很多 p_people(这些是 client 方的人,但他们属于 project)。

所以,我有以下问题:

当我在视图中使用辅助方法“link_to_add_fields”时,我需要传递另一个参数(current_client_id),该参数取决于选择框中当前选择的客户端。

<!-- new.html.erb -->
<p>
<%= f.label :client_id %></br>
<%= f.collection_select :client_id, Client.order("title"), :id, :title %>
</p>
<p>
<%= f.fields_for :p_people do |builder| %>
<%= render "p_person_fields", :f => builder %>
<% end %>
</p>
<p><%= link_to_add_fields "Add Person", f, :p_people, current_client_id %></p>

我需要在辅助方法中动态更改 @people 变量的集合,

# application_helper.rb
def link_to_add_fields(name, f, association, current_client_id)
    new_object = f.object.class.reflect_on_association(association).klass.new
    @people = CPerson.where(:client_id => current_client_id).order(:name) unless current_client_id.blank?
    fields = f.fields_for(association, new_object, :child_index => "new_#{association}") do |builder|
      render(association.to_s.singularize + "_fields", :f => builder)
    end
    link_to_function(name, h("add_fields(this, \"#{association}\", \"#{escape_javascript(fields)}\")"))
end

最终部分使用它:

<!-- _p_person_fields.html.erb -->
<div class="fields">
<p>
<%= f.collection_select :content, @people, :name, :name %>
<%= f.hidden_field :_destroy %>
<%= link_to_function "Remove", "remove_fields(this)" %>
</p>
</div>

这是获取 current_client_id 值的简单 js 函数,但我不知道如何将它传递给我的视图或辅助方法。

// application.js
function current_client_id() {
var current_client_id = $("select#client_id :selected").val();
}

感谢您的帮助!也许有更好的解决方案?

【问题讨论】:

    标签: javascript jquery ruby-on-rails ruby-on-rails-3 parameter-passing


    【解决方案1】:

    如果您使用的是 Rails 3,那么您应该删除 application_helper.rb 中的“h(”:

    link_to_function(name, h("add_fields(this, \"#{association}\", \"#{escape_javascript(fields)}\")"))
    

    link_to_function(name, "add_fields(this, \"#{association}\", \"#{escape_javascript(fields)}\")")
    

    【讨论】:

      【解决方案2】:

      我找到了为项目分配人员的更好方法——使用多选选项。这允许不使用嵌套模型字段。

      1.在两个模型之间使用has_and_belongs_to_many关联:c_person和project。

      2.创建连接表:

      class CreateCPeopleProjects < ActiveRecord::Migration
        def self.up
          create_table :c_people_projects, :id => false do |t|
            t.references :project
            t.references :c_person  
          end  
        end
      
        def self.down
          drop_table :c_people_projects
        end
      end
      

      3.修改new.html.erb和部分。

      <!-- new.html.erb -->
      <p>
      <%= f.label :client_id, "Client" %><br />
      <%= f.collection_select :client_id, @clients, :id, :title %>
      </p>
      <div id="people">
      <%= render "c_people" %>
      </div>
      
      <!-- _c_people.html.erb -->
      <p>
      <%= fields_for :project do |f| %>
       <% if @update_people.blank? %>
       <%= f.collection_select :c_person_ids, @people, :id, :name, {:selected => @project.c_person_ids}, {:multiple => true, :name => "project[c_person_ids][]"} %>
       <% else %>
       <%= f.collection_select :c_person_ids, @update_people, :id, :name, {}, {:multiple => true, :name => "project[c_person_ids][]"} %>
       <% end %>
      <% end %>
      </p>
      

      4.添加js函数获取当前客户端id值,发送到projects_controller,用新集合替换partial。

      jQuery(function($) {
       $(function() {
        $("#project_client_id").change(function() {
        var client_id = $("select#project_client_id :selected").val();
        if (client_id == "") {client_id = "0";}
        $.get("/projects/update_people/" + client_id, function(data){
         $("#people").html(data);
        })
        return false;
        });
       });
      })
      

      5.添加方法到projects_controller 以动态更改人的集合。还有一行更新操作(用于更新 nil 对象)。

        def update
          @project = Project.find(params[:id])
          params[:project][:c_person_ids] ||= []
      
          respond_to do |format|
            if @project.update_attributes(params[:project])
              format.html { redirect_to(@project, :notice => 'Project was successfully updated.') }
              format.xml  { head :ok }
            else
              format.html { render :action => "edit" }
              format.xml  { render :xml => @project.errors, :status => :unprocessable_entity }
            end
          end
        end
      
        def update_people
          @update_people = CPerson.where(:client_id => params[:id]).order(:name) unless params[:id].blank?
          render :partial => "c_people"
        end
      

      6.不要忘记路线:match "/projects/update_people/:id" =&gt; "projects#update_people"

      【讨论】:

        【解决方案3】:

        我不喜欢的一点是,您在真正属于您的控制器的视图助手中使用了逻辑。

        也许更好的方法是使用 current_client_id 对控制器进行 AJAX 调用。然后,该控制器可以获取 @people 对象并发送回一个 js.erb 模板,您可以在其中将部分内容附加到您的视图中。或者它可以发回一个 JSON 对象,并且 AJAX 调用的处理程序将创建新元素以添加到 DOM。

        【讨论】:

          猜你喜欢
          • 2019-07-24
          • 2020-07-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-08-09
          • 2018-02-21
          • 2018-03-01
          • 2015-03-22
          相关资源
          最近更新 更多