<ActionForm/>
<ActionForm/>
是一个特殊的 <Form/>
,它接受一个服务器操作,并在表单提交时自动调度它。这允许你直接从 <form>
调用服务器函数,即使没有 JS/WASM。
过程很简单:
- 使用
#[server]
宏 定义一个服务器函数(参见 服务器函数)。 - 使用
create_server_action
创建一个操作,指定你定义的服务器函数的类型。 - 创建一个
<ActionForm/>
,在action
prop 中提供服务器操作。 - 将命名参数作为具有相同名称的表单字段传递给服务器函数。
注意:
<ActionForm/>
仅适用于服务器函数的默认 URL 编码的POST
编码,以确保作为 HTML 表单的优雅降级/正确行为。
#[server(AddTodo, "/api")]
pub async fn add_todo(title: String) -> Result<(), ServerFnError> {
todo!()
}
#[component]
fn AddTodo() -> impl IntoView {
let add_todo = create_server_action::<AddTodo>();
// 保存从服务器返回的最新值
let value = add_todo.value();
// 检查服务器是否返回了错误
let has_error = move || value.with(|val| matches!(val, Some(Err(_))));
view! {
<ActionForm action=add_todo>
<label>
"Add a Todo"
// `title` 与 `add_todo` 的 `title` 参数匹配
<input type="text" name="title"/>
</label>
<input type="submit" value="Add"/>
</ActionForm>
}
}
真的就这么简单。使用 JS/WASM,你的表单将在没有页面重新加载的情况下提交,将其最近提交的内容存储在操作的 .input()
信号中,将其待处理状态存储在 .pending()
中,等等。(如果需要,请参阅 Action
文档以进行复习。)如果没有 JS/WASM,你的表单将在页面重新加载时提交。如果你调用一个 redirect
函数(来自 leptos_axum
或 leptos_actix
),它将重定向到正确的页面。默认情况下,它会重定向回你当前所在的页面。HTML、HTTP 和同构渲染的强大功能意味着你的 <ActionForm/>
可以正常工作,即使没有 JS/WASM。
客户端验证
因为 <ActionForm/>
只是一个 <form>
,所以它会触发一个 submit
事件。你可以在 on:submit
中使用 HTML 验证或你自己的客户端验证逻辑。只需调用 ev.prevent_default()
即可防止提交。
FromFormData
特征在这里可能会有所帮助,用于尝试从提交的表单中解析你的服务器函数的数据类型。
let on_submit = move |ev| {
let data = AddTodo::from_event(&ev);
// 愚蠢的验证示例:如果待办事项是“nope!”,则不执行
if data.is_err() || data.unwrap().title == "nope!" {
// ev.prevent_default() 将阻止表单提交
ev.prevent_default();
}
}
复杂输入
作为具有嵌套可序列化字段的结构体的服务器函数参数,应使用 serde_qs
的索引符号。
use leptos::*;
use leptos_router::*;
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
struct HeftyData {
first_name: String,
last_name: String,
}
#[component]
fn ComplexInput() -> impl IntoView {
let submit = Action::<VeryImportantFn, _>::server();
view! {
<ActionForm action=submit>
<input type="text" name="hefty_arg[first_name]" value="leptos"/>
<input
type="text"
name="hefty_arg[last_name]"
value="closures-everywhere"
/>
<input type="submit"/>
</ActionForm>
}
}
#[server]
async fn very_important_fn(
hefty_arg: HeftyData,
) -> Result<(), ServerFnError> {
assert_eq!(hefty_arg.first_name.as_str(), "leptos");
assert_eq!(hefty_arg.last_name.as_str(), "closures-everywhere");
Ok(())
}