I am trying to create a form with a list of addresses and allowing the user to delete or create new addresses through Javascript. I’ve used Rails’ fields_for with a child_index: 'new_record' for a similar functionality where I replaced the new_record string with a timestamp when appending the form fields through Javascript (as explained by this Pluralsight tutorial: https://www.pluralsight.com/guides/ruby-on-rails-nested-attributes).
The trick I am looking for is to have similar rendering functionality in Phoenix is how to generate a nested form with a given / custom child index. Currently I am struggling with something like this;
<%= form_for @changeset, Routes.user_path(@conn, :update, @user.id), [data: [controller: "nested-form", action: "nested-form#submit"]], fn f -> %>
<div data-target="nested-form.records">
<%= inputs_for f, :addresses, fn fp -> %>
<%= render __MODULE__, "_address_fields.html", form: fp %>
<% end %>
</div>
<template data-target="nested-form.template">
<%# How do I get a template input group here? %>
<%# In Rails I could do `f.fields_for :addresses, Address.new, child_index: 'NEW_RECORD'` %>
</template>
<% end %>
But I can't figure out how to generate a inputs_for
with Phoenix to create such template.
As @TheAnh commented, the answer is discussed in this gist (https://gist.github.com/mjrode/c2939ee7786b157aab131761c8fb89a9). To provide an answer, I've solved it with the following helper method;
defmodule MyAppWeb.UserView do
use MyAppWeb, :view
def template_inputs_for(changeset, field, fun) do
form = Phoenix.HTML.FormData.to_form(changeset, [])
inputs_for(form, field, fn form ->
id = String.replace(form.id, ~r/\d$/, "NEW_RECORD")
name = String.replace(form.name, ~r/\[\d\]$/, "[NEW_RECORD]")
fun.(%{form | id: id, name: name})
end)
end
end
Which can then be used to generate a "template" field group;
<%= form_for @changeset, Routes.user_path(@conn, :update, @user.id), [data: [controller: "nested-form", action: "nested-form#submit"]], fn f -> %>
<div data-target="nested-form.records">
<%= inputs_for f, :addresses, fn fp -> %>
<%= render __MODULE__, "_address_fields.html", form: fp %>
<% end %>
</div>
<template data-target="nested-form.template">
<%= template_inputs_for User.changeset(%User{addresses: [%Address{}]}), :addresses, fn f -> %>
<%= render __MODULE__, "_address_fields.html", form: f %>
<% end %>
</template>
<% end %>