我是 LiveView、Phoenix 和 Elixir 的新手,我正在努力从表单内容填充 UI。 这是我的代码中的简化版本: 我定义了一个带有一些简单字段的结构:
defmodule MyApp.MyStruct do
defstruct some_integer: 3,
some_string: "",
some_bool: true
end
然后我有一个上下文:
defmodule MyApp.Context do
alias MyApp.MyStruct
def current_struct() do
%MyStruct{}
end
end
它只是返回新创建的具有默认值的结构。稍后我会实施修改。 现在,我需要显示一个填充了这些值的表单并允许修改它们。 这是我的
_live.ex
文件:
defmodule MyAppWeb.ViewLive do
alias MyApp.MyStruct
use MyAppWeb, :live_view
def mount(_params, _session, socket) do
{:ok, assign(socket, form: to_form(Map.from_struct(Context.current_struct())))}
end
# Here I have handle_event methods, but they don't do anything at the moment.
end
最后,这是
.heex
文件:
<div class="container mx-auto my-4">
<.form for={@form} phx-change="change_form" phx-submit="submit_form">
<!-- Number picker -->
<div class="mb-4">
<.label>I want to pick a number here:</.label>
</div>
<div class="flex items-center space-x-4 mb-4">
<label class="cursor-pointer">
<input type="radio" name="some_integer" value="3" class="hidden" checked={Context.current_struct().some_integer == 3}
/>
<span class={"px-4 py-2 rounded-md #{if Context.current_struct().some_integer == 3, do: "bg-gray-400", else: "bg-gray-200"} hover:bg-gray-400"}>
3 of something
</span>
</label>
<!-- More of these integer options -->
<!-- Checkbox -->
<div class="mb-4">
<.input
label="I'd like this to be true or false:"
type="checkbox"
value={Context.current_struct().some_bool}
field={@form[:some_bool]}
/>
</div>
<.button>Submit</.button>
</.form>
</div>
上面的代码现在适用于初始值,但当我选择 7 或 10 而不是 3 时,它会停止工作。 请注意如何获取值或计算背景颜色,我使用
Context.my_struct()
进行计算。
我假设,如果我实现 handle_event("change_form"...)
并在每次更改时修改我的 current_struct()
,那么该更改也将应用于 UI。但我想仅在提交时修改实际结构,同时从@form
获取数据。
我尝试这样做,但失败了。
当我尝试做类似的事情时
value={@form[:some_bool]}
然后就崩溃了。当我尝试使用
input_value()
时,我总是得到 nil,即使 inspect(form)
显示 some_integer
和 some_bool
都具有我期望它们具有的值。
请告诉我如何实现这一目标。
我假设,如果我实现handle_event(“change_form”...)并且 每次更改时修改我的 current_struct() ,那么更改也会 应用于 UI 上。但我只想修改实际结构 提交,同时从@form
获取数据
在
mount()
中,您可以从结构中提取值并将值存储在套接字中,这些值可用于填充 render()
中的表单。用户更改表单中的某些内容后,将调用 handle_event()
,在 handle_event()
中,您可以获得输入到表单中的值并对其执行任何您想要的操作(并且可能将输入的值保存在套接字中) .
此外,在
mount()
中,您可以将原始结构保存在套接字中,并保持不变,直到用户单击“提交”按钮。然后在里面handle_event()
,您可以使用表单中输入的最终值来更新原始结构,然后对更新后的结构执行任何您想要的操作。
这是一个例子:
#========= Your struct code =======
defmodule MyApp.MyStruct do
defstruct some_integer: 3,
some_string: "",
some_bool: true
end
defmodule MyApp.Context do
alias MyApp.MyStruct
def current_struct() do
%MyStruct{}
end
end
#================================
defmodule DemoWeb.DemoLive do
use DemoWeb, :live_view
def mount(_params, _session, socket) do
start_struct = MyApp.Context.current_struct()
initial_form_data = %{
input_int: start_struct.some_integer,
input_string: start_struct.some_string,
input_bool: start_struct.some_bool
}
socket = assign(socket,
my_struct: start_struct,
my_form: to_form(initial_form_data)
)
{:ok, socket}
end
def render(assigns) do
~H"""
<.form for={@my_form} phx-change="changed" phx-submit="save">
<.input label="Some integer:"
field={@my_form[:input_int] }
value = {@my_form.params.input_int }
/>
<.input label="Some string:"
field={@my_form[:input_string]}
value={@my_form.params.input_string}
/>
<.input label="Some bool:"
field={@my_form[:input_bool]}
value={@my_form.params.input_bool}
/>
<.button>Submit</.button>
</.form>
"""
end
def handle_event("changed",
%{"input_int" => entered_int,
"input_string" => entered_string,
"input_bool" => entered_bool
},
socket) do
#Do something with entered_int, entered_string, entered_bool, e.g.
IO.puts("[ME]: The entered integer was: #{entered_int}")
IO.puts("[ME]: The entered string was: #{entered_string}")
IO.puts("[ME]: The entered bool was: #{entered_bool}")
#If needed save the entered int, string, bool in the socket using assign()
{:noreply, socket}
end
def handle_event("save",
%{"input_int" => entered_int,
"input_string" => entered_string,
"input_bool" => entered_bool
},
socket) do
start_struct = socket.assigns.my_struct
updated_struct = %{start_struct | some_integer: entered_int,
some_string: entered_string,
some_bool: entered_bool}
#Do something with updated_struct, e.g.:
IO.inspect(updated_struct, label: "[ME]:")
{:noreply, socket}
end
end