简体   繁体   中英

Dynamically add & remove new but the same fields of a form any amount times

I have a form that has no nested models.

class UserProductsController

  def new
    @user_product = current_user.user_products.build
  end
end

With jquery/javascript i want to add and remove new @user_product fields on the same form. This how it would look normally:

<%= form_for(@user_product) do |f| %>
    <%= f.error_messages %>
      <%= f.text_field :product %>
      <%= f.text_field :address %>
      <%= f.text_field :price %>
    <%= f.submit %>
<% end %>

And I'm trying to achieve:

<%= form_for(@user_product) do |f| %>
      <%= f.error_messages %>
      <%= f.text_field :product_name %>
      <%= f.text_field :address %>
      <%= f.text_field :price %>
      ---New ID(New generated ID, could be any new number in the database)
      <%= f.text_field :product_name %>
      <%= f.text_field :address %>
      <%= f.text_field :price %>
      <%= Remove this Product %> # ajax style, this link removes this product entirely
      ----ID 3----
      <%= f.text_field :product_name %>
      <%= f.text_field :address %>
      <%= f.text_field :price %>
      <%= Remove this Product %>
     -----Add link------
      <%= Add Another Field %> # ajax style adding
   <%= f.submit %>
<% end %>

Notice the new IDs that aren't preset and the one submit button so this way more then one Product can be created at a time by a User. How do i achieve the above?

Thank you.


Answer:

Using the User.rb model you can do what James said. Here is my form that works.

<%= form_for(current_user, :url => user_products_path) do |f| %>
  <%= f.error_messages %>
    <%= f.fields_for :user_products do |builder| %>
     <%= render "user_product_fields", :f => builder %>
    <% end %>
     <%= link_to_add_fields "Add a UserProduct", f, :user_products %>
    <%= f.submit "Create" %>
<% end %>

_user_product_fields.html.erb

<div class="fields">
        <%= f.label :product, "Product" %>
        <%= f.text_field :product %>
        <%= f.label :address, "Address" %>
        <%= f.text_field :address %>
        <%= f.label :price %>
        <%= f.text_field :price %>
        <%= link_to_remove_fields "remove", f %>
</div>

As others have suggested (somewhat unhelpfully), use nested forms.

You need the form to be based on the current_user object with fields_for declaration for:user_products. You will need to set the url for the form to post back to the user_product controller not the user controller using url_for and you will need to adjust the user_product controllers update and create actions to make use of params[:user] instead of params[:user_product]

If you have your accepts_nested_attributes configured properly all should be good.

BTW if you follow those railscasts you will find that the javascript to add new will not work for Rails 3.x

You should use something like this for your view helpers

module ApplicationHelper
  def link_to_remove_fields(name, f)
    f.hidden_field(:_destroy) + link_to_function(name, "remove_fields(this)")
  end

  def link_to_add_fields(name, f, association)
    new_object = f.object.class.reflect_on_association(association).klass.new
    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, "add_fields(this, '#{association}', '#{escape_javascript(fields)}')")
  end
end

and something like this for your javascript in your application.js file

// Place your application-specific JavaScript functions and classes here
// This file is automatically included by javascript_include_tag :defaults
function remove_fields(link) {
  $(link).previous("input[type=hidden]").value = "1";
  $(link).up(".fields").hide();
}

function add_fields(link, association, content) {
  var new_id = new Date().getTime();
  var regexp = new RegExp("new_" + association, "g")
  $(link).up().insert({
    after: content.replace(regexp, new_id)
  });
}

and obviously your form_for need to be refactored to something like this

<%= form_for(current_user, :url => user_product_path) do |f| %>
<!-- add your f.fields_for :user_products here, probably in a rendered partial -->
<%end%>

That should be enough with the rails casts to get you going

You can use cocoon for this.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM