我如何处理 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.ex
的state_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
因此,我遵循了创建动态表单的教程: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.ex
的state_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