nathanvda / cocoon

Dynamic nested forms using jQuery made easy; works with formtastic, simple_form or default forms
http://github.com/nathanvda/cocoon
MIT License
3.08k stars 383 forks source link

Form within a nested form #585

Closed atomical closed 4 years ago

atomical commented 4 years ago

I'm using link_to_add_association to add a form to the page. It adds this form for Hotspot but doesn't add a form for an association that also accepts nested attributes.

I want to add Hotspots and then another form for Savings underneath it. Is there a way for the link helper to add both forms?

nathanvda commented 4 years ago

Hi @atomical I am guessing this is very clear to you, but to me it is not. It would help if you would show me some code, how the associations work, ..

Anyway I am guessing a Hotspot has many savings? And you want a least one to be immediately present when creating a new Hotspot? In that case you could use the wrap_object option (see documentation) which also allows do some extra initialisation. E.g. do something like

= link_to_add_association('add something', f, :hotspots, 
            wrap_object: Proc.new { |hotspot| hotspot.savings.build; hotspot }) 
atomical commented 4 years ago

Yes, the wrap_object option could be helpful.

I got it working but my selector is a bit messed up. When I click to insert on one form it inserts into both forms. I think I need to write a custom selector for the node or traversal option. Is that right?

.instant-savings-codes
  .links
    =link_to_add_association "", f, :savings_codes, {class: |
      "js-add-tis tool-btn ico ico-plus", |
      "data-association-insertion-node" => "tbody.savings_codes", |
      "data-association-insertion-method" => "append", |
      "datadata-association-insertion-traversal" => "closest" }
  %table.nested-fields.edition-table.top-space-table{:cellpadding => "0", :cellspacing => "0", :border => "0", class: ""}
    %thead
      %tr
        %th.header Code
        %th.header Description
    %tbody.savings_codes
      =f.fields_for :savings_codes do |savings_code|
        =render 'savings_code_fields', f: savings_code
nathanvda commented 4 years ago

Your usage of the word "form" is very confusing: there is only one form, and it has nested forms, right? Or do you actually have different forms on the page (referring to the HTML form element, e.g. only one form that will be posted to the server).

Anyways, controlling the insertion behaviour is a bit of a pain when you try to do it like you do it. But if you read the documentation --and granted: there is a lot to read, you also have the option to specify a function that will return the correct insertion-node.

I have no idea how your html looks, so I cannot give a good example, but the example from the documentation is the following


$(document).ready(function() {
    $(".add_sub_task a").
      data("association-insertion-method", 'append').
      data("association-insertion-node", function(link){
        return link.closest('.row').next('.row').find('.sub_tasks_form')
      });
});

So if you can write a function, that from the location of the link can find the correct div to append to, you are good to go.

atomical commented 4 years ago

Yes, one form with nested forms. There is a form within the nested form.

If the nested form is being inserted by after clicking the add button on another nested form would I need to use:

$(".add_sub_task a").on

Or possibly a callback?

nathanvda commented 4 years ago

Confused. Let me explain again.

You are trying to insert a new nested-form, you are having trouble to specify the insertion spot correctly, using the selector option, which probably returns multiple options, because that is what selectors can do.

So instead I suggested to use a function to find the insertion spot (and you have to keep in mind that at the time of finding the insertion spot, the "current location" is the clicked link).

From the view you showed earlier, it would probably look like this:

$(document).ready(function() {
    $(".add_sub_task a").
      data("association-insertion-method", 'append').
      data("association-insertion-node", function(link){
        return link.parent('.instant-savings-codes').find('tbody.savings_codes')
      });
});

So from the link you have to travel up to the surrounding div, and then down to the wanted tbody.savings_codes and then one can append? This probably is not entirely correct, untested obviously, but I hope you get the general idea now.

nathanvda commented 4 years ago

Closed due to inactivity.