jotai-form icon indicating copy to clipboard operation
jotai-form copied to clipboard

Expose validate all atoms method for atomWithFormControls

Open Marko-Matijevic opened this issue 1 year ago • 7 comments

Hello,

Is it possible to expose onSubmit button for atomWithFormControls? Because we want to trigger validation for all form fields. Right now we are passing through all form fields and we set touched to true. Because if the field is not touched, it will not be validated.

Can this be implemented? Or do you maybe have a suggestion how to approach this?

Thanks

Marko-Matijevic avatar Nov 07 '24 14:11 Marko-Matijevic

I don't think I understand the requirement completely.

You want the atomWithFormControls to expose a handleOnSubmit function so that you can trigger validation for all the fields?

A few questions so I understand the requirement more.

  1. You wish to have validations run as soon as the form mounts?
  2. You are currently using the handleFocus function to trigger the validations?

Is that the right understanding ?

barelyhuman avatar Nov 07 '24 14:11 barelyhuman

Hello barelyhuman,

Yes, I would like to have an onSubmit function for triggering validation of all the fields.

  1. No, it is only necessary when the "onSubmit" is triggered.
  2. Right now we are using a "custom" onSubmit method which is going through all of the form items and using "setTouched" we are triggering validation inside items.

carbon

Marko-Matijevic avatar Nov 11 '24 09:11 Marko-Matijevic

Oh okay, I'm assuming that you wish to do one of 2 things and i've created examples for the same.

https://github.com/barelyhuman/jotai-form-control-example

Please check them out and let me know if that is the result you wish to achieve or not.

barelyhuman avatar Nov 11 '24 12:11 barelyhuman

@Marko-Matijevic Please close the issue if the above solves for your use case

barelyhuman avatar Nov 18 '24 08:11 barelyhuman

Hello again, sorry for the late response. I have created a repo where I show the example https://github.com/Marko-Matijevic/jotai-form-control-example.

So we have validation:

  • when item inside the form is changed we are triggering the validation
  • when we press "submit" button we are triggering the validation for all fields.

The errors should not appear when we are mounting the component. Only in above cases mentioned.

Marko-Matijevic avatar Nov 18 '24 15:11 Marko-Matijevic

Any specific reason why you aren't using the onFocus and onBlur event handlers?

barelyhuman avatar Nov 18 '24 16:11 barelyhuman

Cause the change's you've made can be handled with the handlers provided by atom and you need to only maintain the state of submission for the errors to show up, here's the code for it and a screencast of it handling cases mentioned by you.

import { useAtom, useAtomValue, atom } from "jotai";
import { atomWithFormControls, atomWithValidate } from "jotai-form";
import { useState } from "react";
import { z } from "zod";

const name = atomWithValidate("", {
  validate: (v) =>
    z.string().min(1, { message: "Name cannot be empty" }).parse(v),
});
const age = atomWithValidate(17, {
  validate: (v) => z.coerce.number(v).min(18).parse(v),
});
const form = atomWithFormControls(
  { name, age },
  {
    validate: (v) => {
      z.object({
        name: z.string().optional(),
      }).parse(v);
    },
  }
);

export const FormTwo = () => {
  const {
    isValid,
    handleOnChange,
    values,
    touched,
    handleOnFocus,
    handleOnBlur,
    fieldErrors,
  } = useAtomValue(form);
  const [submitted, setSubmitted] = useState(false);

  const onSubmit = (e) => {
    e.preventDefault();
    setSubmitted(true);
    if (!isValid) return;
  };

  return (
    <>
      <h2>
        Default values might not exist and need changes and touched state before
        submitting
      </h2>
      <form onSubmit={onSubmit}>
        <div>
          <label>
            <input
              name="name"
              placeholder="name"
              value={values.email}
              onChange={(e) => handleOnChange("name")(e.target.value)}
              onFocus={(e) => handleOnFocus("name")()}
              onBlur={(e) => handleOnBlur("name")()}
            />
            <small>
              {(submitted || touched.name) && fieldErrors?.name?.message}
            </small>
          </label>
        </div>
        <div>
          <label>
            <input
              type="number"
              name="age"
              placeholder="age"
              value={values.age}
              onChange={(e) => handleOnChange("age")(e.target.value)}
              onFocus={(e) => handleOnFocus("age")()}
              onBlur={(e) => handleOnBlur("age")()}
            />
            <small>
              {(submitted || touched.age) && fieldErrors?.age?.message}
            </small>
          </label>
        </div>
        <button onClick={onSubmit}>Submit</button>
      </form>
    </>
  );
};

https://github.com/user-attachments/assets/74f6a5b3-2043-4426-b01f-b888ffc4d2f1

barelyhuman avatar Nov 18 '24 16:11 barelyhuman