自定义 inputs_for 表单输出的子索引

Customize child index of inputs_for form output

我正在尝试创建一个包含地址列表的表单,并允许用户通过 Javascript 删除或创建新地址。我使用 Rails' fields_for 和 child_index: 'new_record' 来实现类似的功能,在附加表单字段时我用时间戳替换了 new_record 字符串通过 Javascript(如本 Pluralsight 教程所述:https://www.pluralsight.com/guides/ruby-on-rails-nested-attributes)。

我正在寻找的技巧是在 Phoenix 中具有类似的呈现功能,即如何生成具有给定/自定义子索引的嵌套表单。目前我正在为这样的事情苦苦挣扎;

<%= 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 %>

但我不知道如何使用 Phoenix 生成 inputs_for 来创建这样的模板。

正如@TheAnh 评论的那样,这个要点中讨论了答案 (https://gist.github.com/mjrode/c2939ee7786b157aab131761c8fb89a9)。为了提供答案,我使用以下辅助方法解决了它;

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

然后可用于生成“模板”字段组;

<%= 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 %>