5

I have a Rails view that allows many PanelItems to be added to many Panels on a Page.

Models

class Page < ActiveRecord::Base
  has_many :panels
  accepts_nested_attributes_for :panels, allow_destroy: true

class Panel < ActiveRecord::Base
  has_many :panel_items
  accepts_nested_attributes_for :panel_items, allow_destroy: true, reject_if: :all_blank

class PanelItem < ActiveRecord::Base

Views

app/views/pages/_form.html.haml

= simple_form_for @page, html: { class: 'form-inline' } do |form|
  = form.input :name, required: :required, autofocus: :autofocus

  %table.table.table-hover
    %tbody
      = form.simple_fields_for :panels do |panel_form|
        %tr
          %td
            .table-responsive
              %table.table.table-hover
                %tbody.panel-items
                  = panel_form.simple_fields_for :panel_items do |panel_item_fields|
                    = render 'panel_item_fields', f: panel_item_fields
            = link_to_add_association panel_form, :panel_items,
                'data-association-insertion-method' => 'append',
                class: 'btn btn-success pull-right' do
              %span{class: 'glyphicon glyphicon-plus-sign'}
              New item
  = form.button :submit, "Update Page", class: 'btn-success'

app/views/pages/_panel_item_fields.html.haml

%tr.nested-fields
  %td
    = f.input :content_item_id,
        collection: current_site.content_items,
        selected: f.object.content_item_id,
        prompt: 'Select a content item'
  %td
    = link_to_remove_association f, title: 'remove this item',
        data: { toggle: 'tooltip', association: 'panel-item' } do
      %span.sr-only remove this item
      %span{class: 'glyphicon glyphicon-minus-sign'}

I want the New item button to append the panel_item_fields partial at the end of the associated table. I've tried many combinations of data-association-insertion-node and data-association-insertion-traversal attributes with no joy.

Cocoon uses the data- attributes to set the variables insertionTraversal and insertionNode, used in the following jQuery code:

$this[insertionTraversal](insertionNode)

but I don't really know how to read that.

EDIT: If I use:

'data-association-insertion-node' => '.panel-items',
'data-association-insertion-method' => 'append',

The new row gets appended to every table on the page, instead of just the closest table.

Bryan Ash
  • 4,385
  • 3
  • 41
  • 57

2 Answers2

3

It seems that append'ing to a table appends to the tbody, so by making the New item button a sibling of the table:

.table-responsive
  %table.table.table-hover
    %tbody.panel-items
      = panel_form.simple_fields_for :panel_items do |panel_item_fields|
        = render 'panel_item_fields', f: panel_item_fields
  = link_to_add_association panel_form, :panel_items,
      'data-association-insertion-method' => 'append',
      'data-association-insertion-traversal' => 'prev',
      'data-association-insertion-node' => 'table',
      class: 'btn btn-success pull-right' do
    %span{class: 'glyphicon glyphicon-plus-sign'}
    New item

cocoon can now append to the previous table.

Bryan Ash
  • 4,385
  • 3
  • 41
  • 57
2

Did you try with:

 'data-association-insertion-method'    => 'append' 
 'data-association-insertion-node'      => '.panel-items'
 'data-association-insertion-traversal' => 'closest'

[UPDATE: use a function to determine the insertion-node]

A while ago cocoon was updated so the data-association-insertion-node can contain a function to determine the insertion node, and then you can do more elaborate traversals, like first going up to do then go down to determine the correct place.

E.g. something like (copied from the cocoon documentation)

$(".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')
    });
nathanvda
  • 49,707
  • 13
  • 117
  • 139
  • I did try that, with no joy. Using insertionTraversal='parent' returns a the correct element for $this[insertionTraversal](), when I use insertionTraversal='parent'. I have not found anything that I can put in insertionNode to return anything, it's always []. – Bryan Ash Jan 07 '15 at 20:07
  • OK, I think I understand what that jQuery statement actually means. And to achieve what I want, with the structure shown, I would need two traversals. – Bryan Ash Jan 07 '15 at 21:12