I'm using React, MUI and Formik.
I have a table and how do I allow that only one radio
would be selected by row?
This is my codesandbox: CLICK HERE
import { TableCell, TableRow, Radio } from "@mui/material";
import { FastField } from "formik";
import CustomTextField from "./CustomTextField";
const CustomTableRow = ({ row, index }) => {
return (
<TableRow
key={row.id}
sx={{
"&:last-child td, &:last-child th": { border: 0 },
}}
>
<TableCell component="th" scope="row">
<FastField
name={`rows.${index}.attribute`}
component={CustomTextField}
fullWidth
size="small"
/>
</TableCell>
<TableCell>
<FastField
// checked={`rows.${index}.radio1`}
name={`rows.${index}.radio1`}
component={CustomTextField}
type="radio"
fullWidth
/>
</TableCell>
<TableCell>
<FastField
// checked={`rows.${index}.radio2`}
name={`rows.${index}.radio2`}
component={CustomTextField}
type="radio"
fullWidth
/>
</TableCell>
</TableRow>
);
};
CustomTableRow.displayName = "CustomTableRow";
export default CustomTableRow;
initialValues
of Formik
to have a state for the selectedOption
validationSchema
to validate the new selectedOption
fieldsetFieldValue
and values to CustomTableRow
provided by Formik
to CustomTableRow
CustomTableRow
component make a handleChange
function which updates the selectedOption
of that row depend on the selected radio.checked
attribute update conditionally based on selectedOption
of the row.demo.js
import React from "react";
import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
import TableCell from "@mui/material/TableCell";
import TableContainer from "@mui/material/TableContainer";
import TableHead from "@mui/material/TableHead";
import TableRow from "@mui/material/TableRow";
import Paper from "@mui/material/Paper";
import { Box, Button } from "@mui/material";
import AddIcon from "@mui/icons-material/Add";
import { Formik, Form, FieldArray } from "formik";
import CustomTableRow from "./CustomTableRow";
import { array, object, string } from "yup";
const validationSchema = object().shape({
rows: array().of(
object().shape({
attribute: string().required("Select an attribute"),
selectedOption: string().required("Select an option"),
})
),
});
const CustomTable = () => {
return (
<TableContainer component={Paper}>
<Formik
initialValues={{
rows: [
{ id: 1, attribute: "", selectedOption: "radio1" },
{ id: 2, attribute: "", selectedOption: "radio2" },
],
}}
validationSchema={validationSchema}
onSubmit={(values) => {
console.log(values);
}}
>
{({ values, setFieldValue }) => (
<Form>
<FieldArray
name="rows"
render={(arrayHelpers) => (
<React.Fragment>
<Box>
<Button
variant="contained"
onClick={() =>
arrayHelpers.push({
id: Date.now(),
attribute: "",
selectedOption: null,
})
}
startIcon={<AddIcon />}
>
Add New
</Button>
</Box>
<Table sx={{ minWidth: 650 }} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>Attribute</TableCell>
<TableCell>Radio 1</TableCell>
<TableCell>Radio 2</TableCell>
</TableRow>
</TableHead>
<TableBody>
{values.rows.map((row, index) => (
<CustomTableRow
key={row.id}
row={row}
index={index}
setFieldValue={setFieldValue}
values={values}
/>
))}
</TableBody>
</Table>
</React.Fragment>
)}
/>
<Button color="primary" variant="contained" type="submit">
Submit
</Button>
</Form>
)}
</Formik>
</TableContainer>
);
};
export default CustomTable;
CustomTableRow.js
import { TableCell, TableRow, Radio } from "@mui/material";
import { Field } from "formik";
import CustomTextField from "./CustomTextField";
const CustomTableRow = ({ row, index, setFieldValue, values }) => {
const handleChange = (event) => {
setFieldValue(`rows.${index}.selectedOption`, event.target.value);
};
return (
<TableRow
key={row.id}
sx={{
"&:last-child td, &:last-child th": { border: 0 },
}}
>
<TableCell component="th" scope="row">
<Field
name={`rows.${index}.attribute`}
component={CustomTextField}
fullWidth
size="small"
/>
</TableCell>
<TableCell>
<Radio
checked={values.rows[index].selectedOption === "radio1"}
onChange={handleChange}
value="radio1"
name={`rows.${index}.selectedOption`}
/>
</TableCell>
<TableCell>
<Radio
checked={values.rows[index].selectedOption === "radio2"}
onChange={handleChange}
value="radio2"
name={`rows.${index}.selectedOption`}
/>
</TableCell>
</TableRow>
);
};
CustomTableRow.displayName = "CustomTableRow";
export default CustomTableRow;