Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/small-pens-love.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte-ux': patch
---

fix(Form): Only prevent submitting to server if validation fails or no server action/method are defined
19 changes: 16 additions & 3 deletions packages/svelte-ux/src/lib/components/Form.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
let className: string | undefined = undefined;
export { className as class };

/** Endpoint to submit form data */
export let action: string | undefined = undefined;

/** HTTP method to submit form. If action defined, defaults to `post`, else is undefined and will prevent submitted (client-side only)*/
export let method: 'post' | 'get' | 'dialog' | undefined = action != null ? 'post' : undefined;

const settingsClasses = getComponentClasses('Form');

const [_state, draft, errors] = formStore(initial, { schema });
Expand All @@ -24,10 +30,17 @@
</script>

<form
on:submit|preventDefault={(e) => {
draft.commit();
{action}
{method}
on:submit={(e) => {
const result = draft.commit();
if (!result || method === undefined) {
// Prevent submitted to server if validation failed, or no server side action/method set
e.preventDefault();
}
}}
on:reset|preventDefault={(e) => {
on:reset={(e) => {
e.preventDefault();
draft.revert();
}}
class={cls(settingsClasses.root, className)}
Expand Down
1 change: 1 addition & 0 deletions packages/svelte-ux/src/lib/stores/formStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export default function formStore<T extends Objectish = any>(
// Clear errors
errorsStore.set({});
// TODO: Consider using `result.data` in case there are defaults, etc?
return true;
} else {
const errors = {};
for (const issue of result.error.issues) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const actions = {
default: async (event) => {
console.log('Default action');
},
// example: async (event) => {
// console.log('Example action');
// },
};
77 changes: 77 additions & 0 deletions packages/svelte-ux/src/routes/docs/components/Form/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,44 @@
</Form>
</Preview>

<h2>Form submit with method</h2>

<Preview>
<Form method="post" initial={data} on:change={(e) => (data = e.detail)} let:draft let:state>
<TextField
label="Name"
value={draft.name}
on:change={(e) => {
draft.name = e.detail.value;
}}
/>
<Button type="submit">Apply</Button>
<Button type="reset">Cancel</Button>
<div class="mt-2">
<div>state: {JSON.stringify(state)}</div>
</div>
</Form>
</Preview>

<!-- <h2>Form submit with action</h2>

<Preview>
<Form action="?/example" initial={data} on:change={(e) => (data = e.detail)} let:draft let:state>
<TextField
label="Name"
value={draft.name}
on:change={(e) => {
draft.name = e.detail.value;
}}
/>
<Button type="submit">Apply</Button>
<Button type="reset">Cancel</Button>
<div class="mt-2">
<div>state: {JSON.stringify(state)}</div>
</div>
</Form>
</Preview> -->

<h2>zod schema</h2>

<Preview>
Expand Down Expand Up @@ -112,3 +150,42 @@
</div>
</Form>
</Preview>

<h2>zod schema with server submit</h2>

<Preview>
<Form
method="post"
initial={schemaData}
{schema}
on:change={(e) => (schemaData = e.detail)}
let:draft
let:state
let:errors
>
<div class="grid gap-2">
<TextField
label="First Name"
value={draft.firstName}
on:change={(e) => {
draft.firstName = e.detail.value;
}}
error={errors.firstName}
/>
<TextField
label="Last Name"
value={draft.lastName}
on:change={(e) => {
draft.lastName = e.detail.value;
}}
error={errors.lastName}
/>
</div>
<Button type="submit">Apply</Button>
<Button type="reset">Cancel</Button>
<div class="mt-2">
<div>state: {JSON.stringify(state)}</div>
<div>errors: {JSON.stringify(errors)}</div>
</div>
</Form>
</Preview>