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

Ability to clone nested form #589

Closed przbadu closed 4 years ago

przbadu commented 4 years ago

Requirement

My requirement is to add clone/add link to my nested form and here is a sample example which is not working:

NOTE: this example is taken from documentation and I am only passing parent object so that I can add clone button/link in the nested form.

= simple_form_for @project do |f|
  = f.input :name
  = f.input :description
  %h3 Tasks
  #tasks
    = f.simple_fields_for :tasks do |task|
      = render 'task_fields', f: task, project: f # here I am passing project as parent form object
    .links
      = link_to_add_association 'add task', f, :tasks, render_options: {locales: {project: f}}
  = f.submit

_task_fields.html.erb

.nested-fields
  = f.input :description
  = f.input :done, as: :boolean
  = link_to_add_association "clone", project, :tasks, wrap_object: Proc.new {|i| i.description = f.object.description } 
  = link_to_remove_association "remove task", f

Error

Screen Shot 2020-06-24 at 12 06 50 PM

nathanvda commented 4 years ago

The reason why you get this error: the link_to_add_association will also try to render the partial and you are not passing the extra, required parameters to the partial. You do this correctly on the first link_to_add_association but not in the second.

If you notice: the add task has this extra option render_options: {locales: {project: f}} which you will also have to use on your clone link.

przbadu commented 4 years ago

@nathanvda Thanks a lot for your quick response, I am sure I tried that option too....let me try it one more time and update you the status. Thanks.

przbadu commented 4 years ago

So, after I add locales in nested clone link

Screen Shot 2020-06-24 at 1 07 49 PM

I now get recursive call to that nested form partial

Screen Shot 2020-06-24 at 1 10 20 PM

przbadu commented 4 years ago

Well, one more thing I would like to update is, I have tried this clone link in Edit page, but I was just displaying existing values to users without form, and I had that clone link setup like this, and it is working. Clicking on it, is nesting new form and cloning all the line items properly.

This issue is happening whenever I attach clone link in actual nested form. Also note that, I wasn't passing partials example:

= f.simple_fields_for :tasks,  @project.tasks do |task|
 = render 'task_detail_fields', project: f, f: task
end

_task_detail_fields

.nested-fields
  = task.description
  = task.done
  = link_to_add_association "clone", project, :tasks, wrap_object: Proc.new {|i| i.description = f.object.description } 
  = link_to_remove_association "remove task", f

UPDATE

maybe because here, partial name is different, it might be working in this case

nathanvda commented 4 years ago

Maybe you are mistaken about the working of cocoon. The rendering of the partial is done server side. So a "clone" will never work like you expect. Since it is pre-rendered, it will only work for existing items and never for new items. Secondly, since it is pre-rendered on server side, rendering a link_to_add_association will render the partial to be inserted, which includes a link_to_add_association which will render the partial ...

We could work around that, because we do the same for parent-children links, if we can limit the depth it will work. Your work around also seems to work, so that is fine.

However: it will almost never behave like a clone as you expect, as it will only work for already existing and unchanged records --change in the browser will never be taken into account since the partial is pre-rendered on the server (as I said before).

Personally, I would implement a clone as follows: add a button, add some javascript that 1) triggers the link_to_add_assocation click event, and then 2) copies all the fields/values from the to be cloned partial to the newly inserted one.

przbadu commented 4 years ago

@nathanvda Actually I just realised that, you are right, that is pre-rendered on the server, and any changes done in the fields won't get updated, so it will always clone empty line item even if it works, until we keep reloading this link, after each input field change.

Yes, it will require javascript to clone them manually.

Thank you so much for your time.