可以以形式使用的一些简单的html functional components。
- the form component
- construction process
- passing data via hidden input
- a reusable input
- a single select
- a dynamic datalist
表单组件
我们构建了带有一个形式的:live_component
来使用这些HTML组件。我们使用示意性更改MyForm
来验证数据。它基于struct %MyForm{}
导出函数changeset/2
。
我们在需要时在mount/1
中实例化分配,即,如果尚未存在。这些是将发送为数据库的字段。
def mount(socket) do
{:ok,
assign(socket,
changeset: MyForm.changeset(%MyForm{}),
[... other assigns...]
)}
end
我们声明将读取的分配以捕获render/1
中的差异:
def render(assigns) do
assigns = assign(assigns, ....
[...declare the accessed fields...]
~H"""
<div>
<.form for={@changeset} id="my_form"
phx-change="change" phx-submit="send" phx-target={@myself}
class="..."
>
[...HTML function components here...]
</.form>
"""
所有formdata字段都将以“ my_form”的ID
值(例如name="my_form[distance]"
)为单位。
“发送”处理程序将收到表格的表单:
%{"my_form" => %{"val1" => "a", "val2" => 2,...}}
我们在“更改”上添加事件处理程序以解析表格的参数,检查约束并使用changeset
和assigns
上的更改更新套接字。
def handle_event("change", %{"my_form" => params}, socket) do
changeset =
%MyForm{}
|> MyForm.changeset(params)
|> Map.put(:action, :validate)
socket =
socket
|> assign(:changeset, changeset)
[... other assigns...]
{:noreply, socket}
end
我们用compile-time验证(不是运行时)声明组件属性。
attr(:some_attr, :string)
施工过程
- 用法:使用“属性= {@nistion}”的函数。例如:
<.html_function attrib1={@assign1} attr2={@assign2}>
<.inner_code />
</.html_function
-
声明用于编译时间检查的属性:
attr(:attrb1, :string)
-
检查
mount/1
或render/1
中的分配
-
构建功能组件,以使用属性渲染HTML元素。例如:
def html_function(assigns) do
~H"""
<label for={@attrib1}>
<input id={@attrib1} value={attrib2} name=.../>
</label>
...
"""
end
- 如果使用更改的“更改”,请更新带有更改值的套接字分配
传递隐藏输入的示例
我们希望将给定值传递给FormData,但没有明确的输入。您可以使用hidden
属性。
“普通html”方式只是:
<input type="hidden" name="my_form[radius]" value={@distance} />
但是,为了说明该过程,我们使用函数html组件。
- 用法:带有函数的模块SAID
pass_assign
具有使用我们要通过的分配的属性。在下面的情况下,我们的分配中有distance
。
<.pass_assign radius={@distance} />
- 声明属性:
attr(:radius, :float, doc: false)
- 该组件使用属性,然后在提交时将值传递给FormData:
def pass_assign(assigns) do
~H"""
<input type="hidden" value={@radius}
name="my_form[radius]"
/>
"""
end
- 此值没有更改处理程序,该表格将提交:
%{"my_form" => %{"radius" => 12345}}
可重复使用的日期输入的示例
当我们想重用类型date的输入时,一个示例更有趣。
- 用法:用功能
date
导入模块,并将其用作:
@date_class "w-15 rounded-ml"
<.date date={@start_date} name="start"
class_date={@date_class} />
<.date date={@end_date} name="end"
class_date={@date_class} />
您有3个属性和2个分配。
- 在live_component函数
mount/1
中,实例化分配:
# def mount(socket)
{:ok, assign(socket,
...
start_date: Date.utc_today(),
end_date: Date.utc_today() |> Date.add(1)
}
- 声明组件中使用的属性:
attr(:name, :string)
attr(:date, :string)
attr(:class_date, :string)
- 构建函数
date/1
并使用属性:
def date(assigns) do
~H"""
<label for={@name}> <%= @name %>
<input type="date" id={@name}
name={"my_form[#{@name}_date]"}
value={@date}
class={@class_date}
/>
</label>
"""
end
- 更新“更改”事件处理程序中的更改分配:
socket = socket
|> assign(:changeset, changeset)
|> assign(:start_date, params["start_date"])
|> assign(:end_date, params["end_date"])
提交的参数(formData)为:
%{"my_form" => %{"start_date" => 01/01/2023, "end_date" => 02/01/2023}}
tode:示例与dynamic number of attributes:koud19,
有条件的课程
如果用户的状态为“ admin”,我们希望文本颜色为蓝色。
由于属性class
接受列表,我们可以做:
def date(assigns) do
~H"""
<input type="date" id={@name}
name={"myform[#{@name}_date]"}
value={@date}
class={[@user.status == "admin" && "text-blue-700", @class_date]}
/>
"""
end
集成错误
- 我们想集成验证错误。我们可以设计这样的组件:
<.date_err name="my_form[date]"
class="w-30" class_err="mt-1"
date={@date} errors={@changeset.errors}
/>
- 我们添加了额外属性:
attr(:errors, :list)
attr(:class_err, :string)
- 该函数组件具有一个错误类,可以帮助DOM中的位置。
def date_err(assigns) do
messages =
assigns.errors
|> Enum.reduce([], fn {_, {msg, _}}, acc -> [msg | acc] end)
assigns = assign(assigns, :messages, messages)
~H"""
<label for={@name}>
<input type="date" id={@name} name={@name}
value={@date} class={@class}
/>
<span class={["text-red-700", @class_err]}
:for={error <- @messages}
>
<%= error %>
</span>
</label>
"""
end
单个选择菜单的示例
一个更好的示例:我们可以轻松地从单个select功能组件中的菜单中捕获所选值。我们使用boolean html属性selected
从菜单中捕获所选的“选项”,然后将其传递给formdata“ on Change”。
注意:如果选择了多个选择,即使我们使用列表而不是单个字符串,我们也需要管理此列表中的可能更改。
- 用法:我们声明一个带有两个输入的函数
selectl
- 菜单列表和初始选择 - 和四个属性(可能具有更多属性,例如类...)。
<.select options={@menu} choice={@status}
name="my_form[status]" class="form-select w-20"
/>
- 我们在
mount/1
中实例化任务:
# mount(socket)
{:ok,
assign(socket,
changeset: MyForm.changeset(%MyForm{}),
menu: ["" | ~w(a b c)],
status: "",
[...]
}
- 我们声明属性:
attr(:options, :list)
attr(:choice, :string)
attr(:name, :string)
atttr(:class, :string)
- 我们构建具有属性的功能HTML组件
select/1
:
def select(assigns) do
~H"""
<select name={@name} class={@class} id={@name}>
<option
:for={option <- @options}
selected={option == @choice}
>
<%= option %>
</option>
</select>
"""
end
和commit(在“更改”验证之后)新值带有事件处理程序“更改”到分配中:
socket =
socket
|> assign(:changeset, changeset)
|> assign(:status, params["status"])
动态数据学家的示例
一个动态填充的koude25的示例。
我们使用关联的input
将值传递给formdata。
我们希望数据师在用户开始键入时被填充。
- 用法:数据库组件可以是:
<.datalist users={@users} user={@user}/>
-
分配:我们在
mount/1
中实例化两个分配users: []
和user: ""
,
或在需要/需要的情况下将user: assign.current_user
设置在render/1
中。 -
属性:我们声明两个属性
attr(:users, :list)
attr(:user, :string)
- 功能组件是:
def datalist(assigns) do
~H"""
<input list="datalist" id="datalist-input"
name="my_form[user]"
phx-change="search-email"
value={@user}
/>
<datalist id="datalist">
<option :for={user <- @users} value={user} />
</datalist>
"""
end
和“更改”处理程序可以像:
def handle_event("search-email", %{"my_form" => %{"user" => string}}, socket) do
datalist =
MyApp.User.search(string) |> Enum.map(& &1.email)
{:noreply, assign(socket, users: datalist, user: string}
end