複雜表單
什麼是複雜表單?
複雜表單通常包含的資料結構,不僅僅是簡單的鍵/值對。例如,一個人員清單,其中每個人都有自己的電子郵件、電話和街道地址。這實際上是一個物件陣列。
輸入框命名
物件
可以透過在名稱中使用 .
(點)分隔項目來建立巢狀項目。例如,person.name
將被轉換為 { person: { name: 'sam' } }
。
陣列
可以透過在名稱中指定從零開始的索引來建立陣列,無論是頂級陣列還是巢狀陣列。例如,person.pets.0
將被轉換為 { person: { pets: [ 'cat' ] } }
。
範例
建立複雜表單的關鍵在於輸入框的命名。以下是以描述的清單為例
<form>
<input name="person.0.name" value="Sam">
<input name="person.0.email" value="[email protected]">
<input name="person.0.pets.0" value="cat">
<input name="person.0.pets.1" value="dog">
<input name="person.0.address.street" value="1234 Example Ave.">
<input name="person.0.address.city" value="Qwik">
<input name="person.0.address.state" value="IA">
<input name="person.0.address.zip" value="00000">
<input name="person.0.pets.0" value="beaver">
<input name="person.1.name" value="Bonnie">
<input name="person.1.email" value="[email protected]">
<input name="person.1.address.street" value="768 Resolution Way">
<input name="person.1.address.city" value="Jaffa">
<input name="person.1.address.state" value="IL">
<input name="person.1.address.zip" value="01948">
</form>
輸出物件
提交表單後,資料將被解析為如下所示的物件
{
"person": [
{
"name": "Sam",
"email": "[email protected]",
"address": {
"street": "1234 Example Ave.",
"city": "Qwik",
"state": "IA",
"zip": "00000"
},
"pets": ["beaver"]
},
{
"name": "Bonnie",
"email": "[email protected]",
"address": {
"street": "768 Resolution Way",
"city": "Jaffa",
"state": "IL",
"zip": "01948"
}
}
]
}
搭配 Actions 使用
可以使用 zod$ 搭配 routeAction$ 和 globalAction$ 來驗證複雜表單。繼續前面的例子,它看起來像這樣
export const action = routeAction$(
async (person) => {
return { success: true, person, };
},
// Zod schema is used to validate the FormData
zod$({
person: z.array(
z.object({
name: z.string(),
email: z.string().email(),
address: z.object({
street: z.string(),
city: z.string(),
state: z.string(),
zip: z.coerce.number()
}),
pets: z.array(z.string())
})
),
})
);
欄位錯誤也採用點符號(幾乎)
如果您使用點符號,則錯誤訊息也會在 fieldErrors
屬性中以點符號返回。這樣做的優點是輸入框名稱和 fieldError 鍵可以匹配。
對於此操作
export const addPersonAction = routeAction$(
async person => {
return { success: true, person };
},
// Zod schema is used to validate the FormData
zod$({
person: z.object({
name: z.string(),
email: z.string().email(),
address: z.object({
street: z.string(),
city: z.string(),
state: z.string(),
zip: z.coerce.number(),
}),
pets: z.array(z.string()),
}),
})
);
如果所有輸入都錯誤,您將收到以下類型的 fieldErrors
{
"person.name": "Invalid string",
"person.email": "Invalid email",
"person.address.street": "Invalid string",
"person.address.city": "Invalid string",
"person.address.state": "Invalid string",
"person.address.zip": "Invalid number",
"person.pets[]": ["Required"]
}
如果您將 person 設定為陣列,則錯誤訊息將切換為略有不同的符號,如下所示
{
"person[].name": ["Invalid string"],
"person[].email": ["Invalid email"],
"person[].address.street": ["Invalid string"],
"person[].address.city": ["Invalid string"],
"person[].address.state": ["Invalid string"],
"person[].address.zip": ["Invalid number"],
"person[].pets[]": ["Required"]
}
如果您完全忘記為陣列類型賦值,比方說,您完全忘記了表單中的 person。那麼錯誤就會出現在
fieldErrors["person[]"]
中。
這樣您就可以輕鬆地將錯誤訊息與輸入框名稱進行匹配,如下所示
export const useAddPersonAction = routeAction$(
async person => {
console.log(person);
return { success: true, person };
},
zod$({
person: z.object({
name: z.string().min(2),
email: z.string().email(),
address: z.object({
street: z.string().min(2),
city: z.string().min(2),
state: z.string().min(2),
zip: z.coerce.number(),
}),
pets: z.array(z.string().min(2)),
}),
})
);
export default component$(() => {
const testAction = useAddPersonAction();
const renderError = (errorMessage: string | undefined) => {
if (!errorMessage) return null;
return <p class="error">{errorMessage}</p>;
};
return (
<Form action={testAction}>
<input type="email" name="person.email" placeholder="Email" />
{renderError(testAction.value?.fieldErrors?.["person.email"])}
<input type="text" name="person.name" placeholder="Name" />
{renderError(testAction.value?.fieldErrors?.["person.name"])}
<input type="text" name="person.address.street" placeholder="Street" />
{renderError(testAction.value?.fieldErrors?.["person.address.street"])}
<input type="text" name="person.address.city" placeholder="City" />
{renderError(testAction.value?.fieldErrors?.["person.address.city"])}
<input type="text" name="person.address.state" placeholder="State" />
{renderError(testAction.value?.fieldErrors?.["person.address.state"])}
<input type="text" name="person.address.zip" placeholder="Zip" />
{renderError(testAction.value?.fieldErrors?.["person.address.zip"])}
<input type="text" name="person.pets.0" placeholder="Pet 1" />
{renderError(testAction.value?.fieldErrors?.["person.pets[]"]?.[0])}
<button>Send</button>
</Form>
);
});
對於此範例,fieldErrors
如下所示
{
"person.name": "String must contain at least 2 character(s)",
"person.email": "Invalid email",
"person.address.street": "String must contain at least 2 character(s)",
"person.address.city": "String must contain at least 2 character(s)",
"person.address.state": "String must contain at least 2 character(s)",
"person.pets[]": [
"String must contain at least 2 character(s)"
]
}