jaredpalmer / formik

Build forms in React, without the tears 😭
https://formik.org
Apache License 2.0
33.9k stars 2.79k forks source link

How to uncheck already checked checkbox? #3918

Open RanaMuzamal opened 10 months ago

RanaMuzamal commented 10 months ago

Below is the source code for my form. I am using Formik for form handling. Essentially, users are granted permissions for specific modules, with available permissions being read, write, update, or delete. The form includes checkboxes corresponding to the permissions the user already possesses. However, users are currently unable to uncheck these already checked checkboxes. I appreciate any assistance in resolving this issue.

  `import { Field, Form, Formik } from "formik";
  import * as Yup from "yup";
  import { JwtPayload, PermissionType } from "../types";
  import { Modules } from "../types";
  import parseJwt from "../utils/decodeJWT";

  interface UserPermissionFormProps {
    closeModal: () => void;
    onSubmit: (values: PermissionType) => void;
    permissions: PermissionType[];
  }

  const AssignPermissionForm: React.FC<UserPermissionFormProps> = ({
    closeModal,
    onSubmit,
    permissions,
  }) => {
    const validationSchema = Yup.object().shape({
      permissionId: Yup.array().of(Yup.number()).optional(),
    });
    const token = localStorage.getItem("token");
    const user: JwtPayload = parseJwt(token as string);
    const userPermissions = user.permissions;

    return (
      <div className="mx-auto max-w-md">
        <Formik
          initialValues={{}}
          validationSchema={validationSchema}
          onSubmit={(values, { setSubmitting }) => {
            const permissionIds = Object.keys(values);
            onSubmit({
              permissionId: permissionIds,
            });
            setSubmitting(false);
          }}
          enableReinitialize
  >
    {(formik) => (
      <Form className="mb-4  mt-6 rounded bg-white px-10 py-8">
        <h3 className="mb-10 text-center text-2xl font-bold text-gray-700">
          Assign Modules Permission
        </h3>

        <div>
          <label
            htmlFor="permissionIdSelector"
            className="mb-2 block text-sm font-bold text-gray-700"
          >
            Modules
          </label>

          {Object.values(Modules).map((module: string) => {
            const filteredPermissions = permissions.filter(
              (permission) => permission.key === module,
            );
            const read = filteredPermissions.filter(
              (permission) => permission.permission === "read",
            )[0];

            const write = filteredPermissions.filter(
              (permission) => permission.permission === "write",
            )[0];

            const update = filteredPermissions.filter(
              (permission) => permission.permission === "update",
            )[0];

            const _delete = filteredPermissions.filter(
              (permission) => permission.permission === "delete",
            )[0];
            return (
              <li className="list-none items-center gap-2 py-1">
                <span className="text-sm font-bold capitalize">
                  {module}
                </span>
                <div className="flex">
                  {read && (
                    <label className="mr-4 flex items-center gap-2">
                      <Field
                        type="checkbox"
                        id="readCheckBox"
                        name={read.id!.toString()}
                        value={userPermissions[module]?.includes(
                          read.permission,
                        )}
                        onChange={formik.handleChange}
                        checked={userPermissions[module]?.includes(
                          read.permission,
                        )}
                      />
                      Read
                    </label>
                  )}
                  {write && (
                    <label className="mr-4 flex items-center gap-2">
                      <Field
                        type="checkbox"
                        id="writeCheckBox"
                        name={write.id}
                        checked={userPermissions[module]?.includes(
                          write.permission,
                        )}
                        onChange={formik.handleChange}
                      />
                      Write
                    </label>
                  )}
                  {update && (
                    <label className="mr-4 flex items-center gap-2">
                      <Field
                        type="checkbox"
                        id="updateCheckBox"
                        name={update.id}
                        checked={userPermissions[module]?.includes(
                          update.permission,
                        )}
                        onChange={formik.handleChange}
                      />
                      Update
                    </label>
                  )}
                  {_delete && (
                    <label className="mr-4 flex items-center gap-2">
                      <Field
                        type="checkbox"
                        id="deleteCheckBox"
                        name={_delete.id}
                        checked={userPermissions[module]?.includes(
                          _delete.permission,
                        )}
                        onChange={formik.handleChange}
                      />
                      Delete
                    </label>
                  )}
                </div>
              </li>
            );
          })}
        </div>

        <div className="float-right mb-10 mr-[-55px] flex items-center">
          <button
            type="button"
            onClick={closeModal}
            className="secondary-btn mr-2"
          >
            Cancel
          </button>
          <button
            className="primary-btn"
            type="submit"
            disabled={formik.isSubmitting || !formik.isValid}
          >
            {formik.isSubmitting ? "Submitting..." : "Submit"}
          </button>
        </div>
      </Form>
    )}
  </Formik>
</div>

); };

export default AssignPermissionForm;`

Current Behaviour imageBut not be be able to uncheck already checked

Expected Behaviour The user should be able to uncheck already checked checkbox or check any uncheckbox

Version "formik": "^2.4.2", "react": "^18.2.0",

akshay1502 commented 9 months ago

@RanaMuzamal , in the above code, the checked attribute is not controlled by formik due to which its not able to change the state of checkbox. Try setting the InitialValues obj instead,

<Formik
initialValues={{
read: `your logic here`
write: `your logic here` 
update: `your logic here`
delete: `your logic here`
}}
>
  {({formik}) => (
    <Form>
      <label>
        <Field type="checkbox" name="read" onChange={formik.handleChange} value={formik.values.read} >
        read
      </labe>
    </Form>
)}
</Formik>

using above, you won't need to specify the checked attribute as formik will handle the initialValue of checkbox from the initialValues obj. You might also need to refactor your code.