Skip to content

Instantly share code, notes, and snippets.

@vicasas
Created June 6, 2020 20:55
Show Gist options
  • Save vicasas/410b11874267460484febbbe49bfbb1d to your computer and use it in GitHub Desktop.
Save vicasas/410b11874267460484febbbe49bfbb1d to your computer and use it in GitHub Desktop.
Example of how to create a dynamic array form using Formik πŸ™Œ
import React from "react";
import { Divider, Button, TextField } from "@material-ui/core";
import { makeStyles } from "@material-ui/core/styles";
import { FieldArray, Form, Formik, getIn } from "formik";
import * as Yup from "yup";
const validationSchema = Yup.object().shape({
people: Yup.array().of(
Yup.object().shape({
firstName: Yup.string().required("First name is required"),
lastName: Yup.string().required("Last name is required")
})
)
});
const debug = true;
const useStyles = makeStyles(theme => ({
container: {
display: "flex",
flexWrap: "wrap"
},
button: {
margin: theme.spacing(1)
},
field: {
margin: theme.spacing(1)
}
}));
const MyForm = () => {
const classes = useStyles();
return (
<div className={classes.container}>
<Formik
initialValues={{
people: [
{
id: Math.random(),
firstName: "",
lastName: ""
}
]
}}
validationSchema={validationSchema}
onSubmit={values => {
console.log("onSubmit", JSON.stringify(values, null, 2));
}}
>
{({ values, touched, errors, handleChange, handleBlur, isValid }) => (
<Form noValidate autoComplete="off">
<FieldArray name="people">
{({ push, remove }) => (
<div>
{values.people.map((p, index) => {
const firstName = `people[${index}].firstName`;
const touchedFirstName = getIn(touched, firstName);
const errorFirstName = getIn(errors, firstName);
const lastName = `people[${index}].lastName`;
const touchedLastName = getIn(touched, lastName);
const errorLastName = getIn(errors, lastName);
return (
<div key={p.id}>
<TextField
className={classes.field}
margin="normal"
variant="outlined"
label="First name"
name={firstName}
value={p.firstName}
required
helperText={
touchedFirstName && errorFirstName
? errorFirstName
: ""
}
error={Boolean(touchedFirstName && errorFirstName)}
onChange={handleChange}
onBlur={handleBlur}
/>
<TextField
className={classes.field}
margin="normal"
variant="outlined"
label="Last name"
name={lastName}
value={p.lastName}
required
helperText={
touchedLastName && errorLastName
? errorLastName
: ""
}
error={Boolean(touchedLastName && errorLastName)}
onChange={handleChange}
onBlur={handleBlur}
/>
<Button
className={classes.button}
margin="normal"
type="button"
color="secondary"
variant="outlined"
onClick={() => remove(index)}
>
x
</Button>
</div>
);
})}
<Button
className={classes.button}
type="button"
variant="outlined"
onClick={() =>
push({ id: Math.random(), firstName: "", lastName: "" })
}
>
Add
</Button>
</div>
)}
</FieldArray>
<Divider style={{ marginTop: 20, marginBottom: 20 }} />
<Button
className={classes.button}
type="submit"
color="primary"
variant="contained"
// disabled={!isValid || values.people.length === 0}
>
submit
</Button>
<Divider style={{ marginTop: 20, marginBottom: 20 }} />
{debug && (
<>
<pre style={{ textAlign: "left" }}>
<strong>Values</strong>
<br />
{JSON.stringify(values, null, 2)}
</pre>
<pre style={{ textAlign: "left" }}>
<strong>Errors</strong>
<br />
{JSON.stringify(errors, null, 2)}
</pre>
</>
)}
</Form>
)}
</Formik>
</div>
);
};
export default MyForm;
@vicasas
Copy link
Author

vicasas commented Jun 6, 2020

Example in codesandbox

@babaiyu
Copy link

babaiyu commented Jan 13, 2022

Nice gist, i have resolve my problem logic in my code using your solution. Thank u so much @vicasas

@vicasas
Copy link
Author

vicasas commented Jan 13, 2022

How great to read that!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment