ishandutta2007
ishandutta2007

Reputation: 18194

Why isn't Formik group checkbox working if the initial state is loaded from a variable?

import React from "react";
import ReactDOM from "react-dom";
import { Formik, Field, Form } from "formik";

const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const ALL_CELEBS = ["apples", "bananas", "oranges", "grapes"];
const CELEBS = ["apples", "grapes"];
const Basic = () => (
  <div>
    <Formik
      initialValues={{
        result: [],
      }}
      onSubmit={async (values) => {
        await sleep(500);
        alert(JSON.stringify(values, null, 2));
      }}
    >
      {({ values }) => (
        <Form>
          <div role="group" aria-labelledby="checkbox-group">
            {ALL_CELEBS.map((celeb) => (
              <label key={celeb}>
                <Field
                  type="checkbox"
                  name="result"
                  value={celeb}
                  checked={CELEBS.includes(celeb)}
                />
                {celeb}
              </label>
            ))}
          </div>
          <button type="submit">Submit</button>
        </Form>
      )}
    </Formik>
  </div>
);

ReactDOM.render(<Basic />, document.getElementById("root"));

https://codesandbox.io/p/sandbox/floral-tdd-klyz33

If I remove checked attribute everything seems to work fine. I have already read other question on stackoverflow to load checkbox initial state like this, they don't seem to be answering for the group case.

Upvotes: 0

Views: 41

Answers (1)

ishandutta2007
ishandutta2007

Reputation: 18194

Check attribute will make it checked all the time not just the initial values, So we need to remove checked attribute from Field tag, and add values initialValues

initialValues to this:

initialValues={{
   result: CELEBS,
}}

and Field tag to this:

<Field
   type="checkbox"
   name="result"
   value={celeb}
/>

CELEBS is array ie const CELEBS=["apples", "grapes"].

Having name="result" on each Field does automatic checking comparing with each of the names in CELEBS.

I had tried this earlier and was not working which is why I posted on stackoverflow , later realised it wasn't working as CELEBS was not loaded yet. So I had to put a check for it to complete loading before rendering like this:

if (CELEBS){
   <div >
     Entire html goes here
   </div >
}

Upvotes: 0

Related Questions