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 385 forks source link

link_to_add_association not doing anything, no console errors #534

Closed cvandermeer closed 5 years ago

cvandermeer commented 5 years ago

Im using rails 5.2, the url does not change with a # nor does the console give any errors

application.js

//= require rails-ujs
//= require activestorage
//= require materialize
//= require jquery
//= require cocoon
//= require_tree .
nathanvda commented 5 years ago

Hi @cvandermeer, you do realise this is extremely terse and it is impossible for me to say anything useful about this without getting more information. It is borderline rude if you cannot even take the time to clearly explain the problem you are experiencing, and expect that somebody (aka me) will try to figure out what you mean and imagine/assume what you have tried already.

Can you show me at least the view code? And explain in detail what is happening. I imagine the link is rendered correctly, but clicking does not work? This either means your javascript has an error or the partial is empty (and inserting an empty partial will not be visible). Now the question: why is the partial empty?

So, again, please show me your view code. It would help to show me the relevant parts of the model and controller as well.

cvandermeer commented 5 years ago

:o jeez, im sorry....

Not sure which code you would have wanted so was waiting for a response to get into the right direction. Here is all then i guess:

_form.html.erb

<%= form_for(@client) do |f| %>
  <div class='row'>
    <% if @client.errors.any? %>
      <ul>
        <% @client.errors.full_messages.each do |msg| %>
          <li><%= msg %></li>
        <% end %>
      </ul>
    <% end %>

    <div class='input-field col s6'>
      <%= f.text_field :firstname %>
      <%= f.label 'Voornaam' %>
    </div>

    <div class='input-field col s6'>
      <%= f.text_field :lastname %>
      <%= f.label 'Achternaam' %>
    </div>

    <%= f.label 'Profielfoto' %>
    <div class='input-field inline'>
      <%= f.file_field :avatar %>
    </div>

    <div class='input-field col s12'>
      <%= f.text_field :pi_serial %>
      <%= f.label 'Raspberry serienummer' %>
    </div>

    <div class='input-field col s12'>
      <%= f.select :dashboard_orientation, Client.dashboard_orientations.keys %>
      <%= f.label 'Dashboard orientatie' %>
    </div>

    <h4>Account:</h4>
    <%= f.fields_for :user do |user| %>
      <div class='input-field'>
        <%= user.email_field :email %>
        <%= user.label 'E-mail' %>
      </div>
      <div class='input-field'>
        <%= user.password_field :password %>
        <%= user.label 'Wachtwoord' %>
      </div>
      <div class='input-field'>
        <%= user.password_field :password_confirmation %>
        <%= user.label 'Wachtwoord bevestiging' %>
      </div>
    <% end %>

    <h4>Gebeurtenissen:</h4>

    <%= f.fields_for :events do |event| %>
      <div class='col s3'>
        <div class='card'>
          <div class='card-content'>
            <%== render 'event_fields', f: event %>
          </div>
        </div>
      </div>
    <% end %>
    <%= link_to_add_association '+', f, :events %>

    <div class='col s12'>
      <%= f.submit @client.persisted? ? 'Bewerken' : 'Toevoegen', class: 'btn' %>
    </div>
  </div>
<% end %>

_event_fields.html.erb

<div class='input-field'>
  <%= f.text_field :date, class: 'datepicker', value: (f.object.date || Date.current).strftime('%d-%m-%Y') %>
  <%= f.label 'Datum' %>
</div>

<div class='input-field'>
  <%= f.text_field :starttime, class: 'timepicker', value: (f.object.starttime || Time.now).strftime('%H:%M') %>
  <%= f.label 'Starttijd' %>
</div>

<div class='input-field'>
  <%= f.text_field :endtime, class: 'timepicker', value: (f.object.endtime || Time.now + 1.hour ).strftime('%H:%M') %>
  <%= f.label 'Eindtijd' %>
</div>

<div class='input-field'>
  <%= f.collection_select :pictogram_id, Pictogram.order(:name), :id, :name, include_blank: true %>
  <%= f.label 'Pictogram' %>
</div>
<%= link_to_remove_association 'X', f %>

View in browser image

The Add link

<a class="add_fields" data-association="event" data-associations="events" data-association-insertion-template="<div class='input-field'>
  <input class=&quot;datepicker&quot; value=&quot;23-01-2019&quot; type=&quot;text&quot; name=&quot;client[events_attributes][new_events][date]&quot; id=&quot;client_events_attributes_new_events_date&quot; />
  <label for=&quot;client_events_attributes_new_events_Datum&quot;>Datum</label>
</div>

<div class='input-field'>
  <input class=&quot;timepicker&quot; value=&quot;11:11&quot; type=&quot;text&quot; name=&quot;client[events_attributes][new_events][starttime]&quot; id=&quot;client_events_attributes_new_events_starttime&quot; />
  <label for=&quot;client_events_attributes_new_events_Starttijd&quot;>Starttijd</label>
</div>

<div class='input-field'>
  <input class=&quot;timepicker&quot; value=&quot;12:11&quot; type=&quot;text&quot; name=&quot;client[events_attributes][new_events][endtime]&quot; id=&quot;client_events_attributes_new_events_endtime&quot; />
  <label for=&quot;client_events_attributes_new_events_Eindtijd&quot;>Eindtijd</label>
</div>

<div class='input-field'>
  <select name=&quot;client[events_attributes][new_events][pictogram_id]&quot; id=&quot;client_events_attributes_new_events_pictogram_id&quot;><option value=&quot;&quot;></option>
<option value=&quot;9&quot;>Avond</option>
<option value=&quot;10&quot;>Dag</option>
<option value=&quot;8&quot;>Middag</option>
<option value=&quot;11&quot;>Namiddag</option>
<option value=&quot;7&quot;>Ochtend</option>
<option value=&quot;2&quot;>Ontbijten</option>
<option value=&quot;12&quot;>Open dienst</option>
<option value=&quot;1&quot;>Opstaan</option>
<option value=&quot;6&quot;>Slapen</option>
<option value=&quot;4&quot;>Spelletje doen</option>
<option value=&quot;3&quot;>Tanden poetsen</option>
<option value=&quot;13&quot;>Tiny Kok</option>
<option value=&quot;5&quot;>wek-dienst</option></select>
  <label for=&quot;client_events_attributes_new_events_Pictogram&quot;>Pictogram</label>
</div>
<input type=&quot;hidden&quot; name=&quot;client[events_attributes][new_events][_destroy]&quot; id=&quot;client_events_attributes_new_events__destroy&quot; value=&quot;false&quot; /><a class=&quot;remove_fields dynamic&quot; href=&quot;#&quot;>X</a>
" href="#">+</a>

This either means your javascript has an error or the partial is empty

Like i said no javascript errors and the url does not even change with a '#' so it looks like its not even trying to do anything.

Mirv commented 5 years ago

Hi @cvandermeer ... have you hit up any of the other files while waiting for help? I'm kind of swamped but noticed this was 3 days old ... from the 2nd link you definitely want to confirm your clicks are putting console ... see inside it for further details ... or close issue if it's resolved ...

https://github.com/nathanvda/cocoon/wiki/Common-Issues--&-Errors https://github.com/nathanvda/cocoon/wiki/Trouble-shooting:-Jquery-issues

nathanvda commented 5 years ago

So now I am thinking that it actually works, but is just not displayed correctly. In your fields_for you add the surrounding divs col-sm-3 and card but it is not in the event-partial, so this will just insert the fields without the "card", without even a surrounding div, so this would mess up the layout.

So what happens if you change the code as follows:

<%= f.fields_for :events do |event| %>
   <%= render 'event_fields', f: event %>
<% end %>
<%= link_to_add_association '+', f, :events %>

and then in your _event_fields partial write

  <div class='col s3 nested-fields'>
    <div class='card'>
      <div class='card-content'>
        <% ... your original event-fields-partial %>
      </div>
    </div>
  </div>

Does that make a difference? BTW what is the meaning of the <%== is that something special/new?

cvandermeer commented 5 years ago

<%== is a typo, although it can be used to display raw just like.html_safe

I turns out it was indeed working but it was adding them to the top of the form (and the form is long) instead of the top of fields for.

Adding the part of a nested events to a fieldset element (as in the cocoon form demo) still adds it outside of that image

Shouldn't it be added at the end?

Now its just deletion that does not work, these are the last 2 elements of an event from inspecting:

<input type="hidden" name="client[events_attributes][4][_destroy]" id="client_events_attributes_4__destroy" value="false">
<a class="remove_fields dynamic" href="#">Remove</a>
nathanvda commented 5 years ago

You probably already solved this yourself, but for completeness

The default insertion behaviour is to look for the parent-div and insert it before that. This works if you follow the structure of the view as in the examples (a div with all nested items, and the link in a separate div), but it is only a default, the insertion behaviour is easy to overrule, see documentation.

Also as documented, removing relies on the presence of a surrounding div with class .nested-fields or a self-selected wrapper class. So in your case you would want something like _event_fields.html.erb

  <div class='col s3 nested-fields'>
    <div class='card'>
      <div class='card-content'>
        ...
      </div>
    </div>
  </div> 
cvandermeer commented 5 years ago

This solves it, Thankyou