我如何处理 Phoenix Live View 中的嵌套表单操作?

How I could handle nested form action in Phoenix Live View?

因此,我遵循了创建动态表单的教程:http://blog.plataformatec.com.br/2016/09/dynamic-forms-with-phoenix/

好吧,这是我的真人input_helpers.ex:

defmodule Conts.InputHelpers do
  @moduledoc """
  Define <%= input f, :pass, type: :password_input %> syntax
  to create dynamic form inputs
  """

  use Phoenix.HTML

  alias Phoenix.HTML.Form, as: PhxForm
  import ContsWeb.ErrorHelpers, only: [error_tag: 2]

  @label_opts "basic-form-label"
  @input_opts "basic-form-input"

  def input(form, field, opts \ []) do
    label_text = opts[:label] || humanize(field)
    type = opts[:type] || PhxForm.input_type(form, field)
    additional_classes = opts[:class] || ""

    label_opts = [class: @label_opts]

    input_opts = [
      class: "#{@input_opts} #{state_class(form, field)} #{additional_classes}",
      id: opts[:id]
    ]

    label_opts = if opts[:id], do: [for: opts[:for]] ++ label_opts, else: label_opts

    content_tag :fieldset do
      label = label(form, field, label_text, label_opts)
      input = input(type, form, field, input_opts)
      error = error_tag(form, field)
      error = if Enum.empty?(error), do: "", else: error

      [label, input, error]
    end
  end

  defp state_class(form, field) do
    cond do
      # The form was not yet submitted
      !form.action -> ""
      form.errors[field] -> "border-red-500"
      # we don't need any additional style at all
      # only with focus:within
      true -> ""
    end
  end

  # Implement clauses below for custom inputs.
  # defp input(:datepicker, form, field, input_opts) do
  #   raise "not yet implemented"
  # end
  defp input(:password_confirmation, form, field, input_opts) do
    apply(PhxForm, :password, [form, field, input_opts])
  end

  defp input(type, form, field, input_opts) do
    apply(PhxForm, type, [form, field, input_opts])
  end
end

在这个项目中,我们有一个 cliente 和一个 user 模式,具有 1-1 关系!

在实时视图模板中,我做了:


<%= input f, :nome, label: "Nome completo", phx_debounce: "blur" %>

<%= input f, :telefone, label: "Número de telefone", phx_debounce: "blur", class: "mobile-masked" %>

<%= inputs_for f, :user, fn u -> %>
  <%= input u, :email, phx_debounce: "blur" %>

  <%= input u, :password, label: "Senha", phx_debounce: "blur" %>

  <%= input u, :password_confirmation, label: "Confirme a Senha", phx_debounce: "blur" %>
<% end %>

前两个字段来自 cliente,其他来自 user 变更集。当验证开始时,即用户开始键入输入,cliente 的字段正确应用 border-red-500 class,但是 user 的字段没有!

我调试它,发现当它试图验证用户变更集的任何字段时,在input_helpers.exstate_class函数中,它落到了!form.acton子句。

我的问题是:如何处理这个嵌套表单操作?为什么会落入上述cond条款?

这是演示问题的 GIF:

嵌套字段缺少 :action 字段。在父窗体上,通常是:validate.

有一种厚颜无耻的“hacky”方式可以实现你想要的。只需将您的 HTML 更改为:

<%= inputs_for f, :user, fn u -> %>

对此:

<%= for u <- inputs_for(f, :user) |> Enum.map(&Map.put(&1, :action, :validate)) do %>

:P