Skip to content

Commit

Permalink
Add isSubmitAttempt on useForm (#90)
Browse files Browse the repository at this point in the history
* feat: add isSubmitAttempt to useForm

* chore: add `isSubmitAttempt` to changeset

* test: add tests for isSubmitAttempt in useForm

* fix: reset isSubmitAttempt on form reset

* test: add reset functionality test for isSubmitAttempt state

* feat: rename `isSubmitAttempt` to `isSubmitAttempted` in useForm

* chore: changeset typo
  • Loading branch information
s8n11c authored Dec 29, 2024
1 parent 67cc35c commit 145bc46
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 8 deletions.
5 changes: 5 additions & 0 deletions .changeset/clean-falcons-flow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@formwerk/core': minor
---

feat: add `isSubmitAttempted` to `useForm`
57 changes: 57 additions & 0 deletions packages/core/src/useForm/useForm.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,63 @@ describe('form submit', () => {
expect(wasSubmitted.value).toBe(false);
}
});

test('Can detect wether was attempted to submit or not ', async () => {
const { isSubmitAttempted, handleSubmit } = await renderSetup(() => {
return useForm({ initialValues: { foo: 'bar' } });
});

const cb = vi.fn();
const onSubmit = handleSubmit(v => cb(v.toObject()));

expect(isSubmitAttempted.value).toBe(false);
await onSubmit(new Event('submit'));
expect(isSubmitAttempted.value).toBe(true);
});

test('Can detect wether it attempt to submit even the validation fails', async () => {
const { isSubmitAttempted, handleSubmit } = await renderSetup(() => {
return useForm({ initialValues: { foo: 'bar' } });
});

const cb = vi.fn();
const onSubmit = handleSubmit(v => cb(v.toObject()));

expect(isSubmitAttempted.value).toBe(false);
await onSubmit(new Event('submit'));
expect(isSubmitAttempted.value).toBe(true);
});

test('Can detect wether it attempt to submit even the submission fails', async () => {
const { isSubmitAttempted, handleSubmit } = await renderSetup(() => {
return useForm({ initialValues: { foo: 'bar' } });
});

try {
const cb = vi.fn(() => Promise.reject());
const onSubmit = handleSubmit(() => cb());

expect(isSubmitAttempted.value).toBe(false);
await onSubmit(new Event('submit'));
} catch {
expect(isSubmitAttempted.value).toBe(true);
}
});

test('Can reset the is submit attempt state', async () => {
const { isSubmitAttempted, handleSubmit, reset } = await renderSetup(() => {
return useForm({ initialValues: { foo: 'bar' } });
});

const cb = vi.fn();
const onSubmit = handleSubmit(v => cb(v.toObject()));

expect(isSubmitAttempted.value).toBe(false);
await onSubmit(new Event('submit'));
expect(isSubmitAttempted.value).toBe(true);
await reset();
expect(isSubmitAttempted.value).toBe(false);
});
});

describe('form dirty state', () => {
Expand Down
18 changes: 10 additions & 8 deletions packages/core/src/useForm/useForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,14 +134,12 @@ export function useForm<
}

const transactionsManager = useFormTransactions(ctx);
const { actions, isSubmitting, submitAttemptsCount, wasSubmitted, ...privateActions } = useFormActions<
TInput,
TOutput
>(ctx, {
disabled,
schema: props?.schema as StandardSchema<TInput, TOutput>,
scrollToInvalidFieldOnSubmit: props?.scrollToInvalidFieldOnSubmit ?? true,
});
const { actions, isSubmitting, submitAttemptsCount, wasSubmitted, isSubmitAttempted, ...privateActions } =
useFormActions<TInput, TOutput>(ctx, {
disabled,
schema: props?.schema as StandardSchema<TInput, TOutput>,
scrollToInvalidFieldOnSubmit: props?.scrollToInvalidFieldOnSubmit ?? true,
});

function getErrors() {
return ctx.getErrors();
Expand Down Expand Up @@ -224,6 +222,10 @@ export function useForm<
* Whether the form was submitted, which is true if the form was submitted and the submission was successful.
*/
wasSubmitted,
/**
* Whether the form was submitted, wether the validity or the submission was successful or not.
*/
isSubmitAttempted,
/**
* Whether the specified field is dirty.
*/
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/useForm/useFormActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export function useFormActions<TForm extends FormObject = FormObject, TOutput ex
) {
const isSubmitting = shallowRef(false);
const submitAttemptsCount = shallowRef(0);
const isSubmitAttempted = shallowRef(false);
const wasSubmitted = shallowRef(false);
const [dispatchSubmit, onSubmitAttempt] = createEventDispatcher<void>('submit');
const {
Expand All @@ -86,6 +87,7 @@ export function useFormActions<TForm extends FormObject = FormObject, TOutput ex
return async function onSubmit(e?: Event) {
e?.preventDefault();
isSubmitting.value = true;
isSubmitAttempted.value = true;
submitAttemptsCount.value += 1;

// No need to wait for this event to propagate, it is used for non-validation stuff like setting touched state.
Expand Down Expand Up @@ -151,6 +153,7 @@ export function useFormActions<TForm extends FormObject = FormObject, TOutput ex
form.revertValues();
form.revertTouched();
submitAttemptsCount.value = 0;
isSubmitAttempted.value = false;

if (state?.revalidate ?? true) {
await validate();
Expand All @@ -177,6 +180,7 @@ export function useFormActions<TForm extends FormObject = FormObject, TOutput ex
isSubmitting,
submitAttemptsCount,
wasSubmitted,
isSubmitAttempted,
};
}

Expand Down

0 comments on commit 145bc46

Please sign in to comment.