Reusable table component with Reactjs and material UI - javascript

I came from Vue.js Vuetify.js background.Vuetify.js has v-data-table component.
Simply we pass headers and items to generate a nice table.
<v-data-table
:headers="headers"
:items="desserts"
></v-data-table>
If we want to add a button, image, or something like that to a table cell
What we do is
<v-data-table :headers="headers" :items="items" >
<template v-slot:item.images="{ item }">
<v-img
v-if="item.images"
max-width="150px"
:src="item.images"
contain
></v-img>
</template>
<template v-slot:item.update="{ item }">
<v-btn
#click="
$router.replace({
path: '/create-product',
query: { id: item.id },
})
"
>
<v-icon>edit</v-icon>
</v-btn></template
>
</v-data-table>
This is very clean and easy.
In React.js also I could achieve the first thing using this
export default function ReusableTable({ headers, items }) {
return (
<Grid container>
<Grid item>
<Card>
<CardContent>
<TableContainer component={Paper}>
<Table>
<TableHead>
<TableRow>
{headers.map((header, i) => (
<TableCell key={i}>{header.text.toUpperCase()}</TableCell>
))}
</TableRow>
</TableHead>{' '}
<TableBody>
{items.map((item, i) => (
<TableRow key={i}>
{headers.map(({ value }) => (
<TableCell key={value}>{item[value]}</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</CardContent>
</Card>
</Grid>
</Grid>
);
}
Here also I pass the headers and items.
I want to display buttons, links, images, chips (UI) for certain columns in the table. How do I achieve that in the React world?
If I further explain, I want to pass items array (array of object). Object's imageSRC property should render with an img tag. Something like that.

Something like this should work. This is conditionally rendering an image tag if there is an item.images as stated in your question. Next it will render a Material Button if item.update exists. Alternatively, it simply renders the item[value].
Here is abbreviated code:
export default function ReusableTable({ headers, items }) {
const dynamicRender = (item, value)=>{
if(item && item.images){
return <img src=`${item.images}`/>
} else if(item && item.update){
return <Button href="/create-product">Link</Button>
} else {
return item[value];
}
}
return (
<TableBody>
{items.map((item, i) => (
<TableRow key={i}>
{headers.map(({ value }) => (
<TableCell key={value}>{dynamicRender(item, value)}</TableCell>
))}
</TableRow>
))}
</TableBody>
);
}

Try something like this
import React from "react";
import TableContainer from "#material-ui/core/TableContainer";
import Table from "#material-ui/core/Table";
import Paper from "#material-ui/core/Paper";
import TableHead from "#material-ui/core/TableHead";
import TableRow from "#material-ui/core/TableRow";
import TableCell from "#material-ui/core/TableCell";
import TableBody from "#material-ui/core/TableBody";
import { getSlots } from 'helpers/Slots'
const BaseTable = ({ headers, items, children, ...otherProps }) => {
const [actions] = getSlots(['actions'], children)
const tableConfig = {
size: "small",
}
const rowConfig = {
...otherProps,
}
const dynamicRenderer = (item, value) => {
if (value === 'actions') {
return children(item)
} else {
return item[value]
}
}
return (
<>
<TableContainer component={Paper}>
<Table {...tableConfig}>
<TableHead>
<TableRow {...rowConfig}>
{headers.map((header, i) => (
<TableCell key={i}>{header.label}</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{items.map((item, i) => (
<TableRow key={i} {...rowConfig}>
{headers.map(({ value }) => (
<TableCell key={value}>{dynamicRenderer(item, value)}</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</>
)
}
export default BaseTable
Then added helpers
import React from "react";
const Slot = ({ children }) => <>{children}</>
const getSlots = ( names, children) => {
return names.map(name => {
let slot = null;
React.Children.forEach(children, child => {
if (!React.isValidElement(child)) {
return;
}
if (child.type === Slot && (child.props).name === name) {
slot = React.cloneElement(child);
}
});
return slot;
});
}
export { Slot, getSlots }
import React, { useState, useEffect } from "react"
import Grid from '#material-ui/core/Grid'
import BaseTable from 'helpers/Table'
import { Slot } from 'helpers/Slots'
import PencilBoxOutline from 'mdi-react/PencilBoxIcon'
import DeleteOutline from 'mdi-react/DeleteIcon'
const headers = [
{value: 'name', label: 'Name'},
{value: 'age', label: 'Age'},
{value: 'gender', label: 'Gender'},
{value: 'registeredDate', label: 'Date of Registration'},
{value: 'requirements', label: 'Semester Requirements'},
{value: 'percentage', label: 'Percentage (%)'},
{value: 'actions', label: 'Actions'},
]
const items = [
{
id: 1,
requirements: 'Pay at least 50% ',
percentage: '10%',
name: "John Doe",
age: 30,
registeredDate: "2021/10/30",
gender: "Male"
},
{
id: 2,
requirements: 'Just go with it',
percentage: '50%',
name: "Jane Doe",
age: 40,
registeredDate: "2021/10/30",
gender: "Female"
},
]
const Test = () => {
return (
<Grid container spacing={4}>
<Grid item xs={12}>
<Grid container justifyContent="space-between" spacing={2}>
<Grid item></Grid>
<Grid item sm={9}></Grid>
</Grid>
<BaseTable headers={headers} items={items}>
{(item) => (
<Slot name="actions">
<PencilBoxOutline onClick={(item) => onOpenDialog(item)}/>
<DeleteOutline onClick={(item) => onDelete(item)} />
</Slot>
)}
</BaseTable>
</Grid>
</Grid>
)
}
export default Test

Related

Can we pass callback function in object prop in React?

I want to pass a callback function in a prop of type object. I have created a custom component for data table in that component I am passing columns, data and actions as props.
actions props is an array of objects with handler callback function linked to each element.
Here is my Data table component code
const DataTable = ({ columns, data, actions }) => {
return <>
<TableContainer>
<Table sx={{ minWidth: 650 }} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>#</TableCell>
{
columns.map((item) => {
return (<TableCell key={item.key}>{item.label}</TableCell>);
})
}
{
actions && <TableCell>Actions</TableCell>
}
</TableRow>
</TableHead>
<TableBody>
{data.map((row, index) => (
<TableRow
key={row.id}
sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
>
<TableCell>
{index + 1}
</TableCell>
{
columns.map(item => {
return (<TableCell key={item.key}>{row[item.key] ? row[item.key] : ''}</TableCell>);
})
}
<TableCell>
{
actions.map((element) => {
return (<React.Fragment key={element.label}><span onClick={(row) => {element.handler(row.id)}}>{element.icon}</span></React.Fragment>)
})
}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
<Pagination count={1} />
</TableContainer>
</>
}
export default DataTable;
and here is code of using that data table
const [data, setData] = useState([]);
const columns = [
{
key: "provider",
label: "Provider",
},
{
key: "phone_number",
label: "Phone Number",
},
{
key: "status",
label: "Status",
},
];
const actions = [
{
icon: <VisibilityIcon sx={{ color: '#1976d2', cursor: 'pointer' }} />,
label: 'View',
handler: ''
},
{
icon: <DeleteIcon sx={{ color: '#1976d2', marginLeft: '4px', cursor: 'pointer' }} />,
label: 'Delete',
handler: deleteHandler
}
];
// Fetching data from api
const deleteHandler = async (id) => {
// Calling delete api
}
return <>
<Card>
<CardContent>
<DataTable columns={columns} data={data} actions={actions} />
</CardContent>
</Card></>;
Now on clicking on any action button I am getting this error
TypeError: element.handler is not a function
Is there any specific way using which i can pass these callback function inside prop object.
You have to check if the element.handelr is a function or not
// in your child component
const actionFn = (id, handler) => {
if (typeof handler !== 'function' ) {
return;
}
handler(row.id);
}
// JSX
<TableCell>
{
actions.map((element) => {
return <React.Fragment key={element.label}>
<span onClick={(row) => {actionFn(row.id, element.handler)}}>{element.icon}</span>
</React.Fragment>
})
}
</TableCell>
Also move const deleteHandler above const actions

When changing the state of parent from child component setState function becomes undefined

Okay so I have a really strange error in my react application.
Basically I have a function that handles an input change and changes the state from the parent component.
import React from "react";
import PaginationExtended from "../PaginationExtended/PaginationExtended";
import { ScreenContext } from "../../helpers/context";
import {
Paper,
TableCell,
TableContainer,
Table,
TableBody,
TableHead,
TableRow,
Checkbox,
TextField,
} from "#material-ui/core";
import EnhancedTableToolbar from "../EnhancedToolBar/EnhancedToolBar";
import uuid from "react-uuid";
import findWithAttr from "../../helpers/findAttr";
import objectInArray from "../../helpers/objectInArray";
import ItemTableRow from "./ItemTableRow/ItemTableRow";
const ItemTable = (props) => {
const screen = React.useContext(ScreenContext);
const handleCheckboxClick = (e) => {
if (e.target.checked) {
props.setDynamicRows((prevState) => {
const newTableData = [...prevState];
console.log(newTableData);
const rowIndex = findWithAttr(props.rows, "id", parseInt(e.target.id));
const newRow = {};
props.headings.forEach((heading) => {
newRow[heading.text.toLowerCase()] =
props.rows[rowIndex][heading.default];
});
newRow.id = e.target.id;
newRow.type = "accepted";
newRow.files = [];
newRow.category = props.title;
newTableData.push(newRow);
return newTableData;
});
} else {
props.setDynamicRows((prevState) => {
const newTableData = [...prevState];
console.log(newTableData);
const rowIndex = findWithAttr(
newTableData,
"id",
parseInt(e.target.id)
);
newTableData.splice(rowIndex, 1);
return newTableData;
});
}
};
const handleInputChange = () => {
console.log(1);
props.setDynamicRows((prevState) => {
const newTableData = [...prevState];
console.log(newTableData);
const rowIndex = findWithAttr(newTableData, "id", props.row.id);
newTableData[rowIndex][e.target.name] = e.target.value;
return newTableData;
});
};
return (
<Paper className={`${props.className}`}>
<EnhancedTableToolbar
screen={screen}
title={props.title}
// record={props.rows}
// setRows={setRows}
/>
<TableContainer>
<Table aria-label="simple table">
<TableHead>
<TableRow>
{props.hasCheckbox && <TableCell padding="checkbox" />}
{props.headings.map((heading) => {
return (
<TableCell className={"text-nowrap"} align="right">
{heading.text}
</TableCell>
);
})}
</TableRow>
</TableHead>
<TableBody>
{props.rows.map((row, index) => {
if (!props.inputTable) {
return (
<ItemTableRow
title={props.title}
headings={props.headings}
handleCheckboxClick={handleCheckboxClick}
dynamicRows={props.dynamicRows}
index={index}
row={row}
hasCheckbox={props.hasCheckbox}
setDynamicRows={props.setDynamicRows}
/>
);
} else {
if (row.type === "accepted" && row.category === props.title) {
return (
<ItemTableRow
title={props.title}
headings={props.headings}
handleCheckboxClick={handleCheckboxClick}
dynamicRows={props.dynamicRows}
index={index}
row={row}
hasCheckbox={props.hasCheckbox}
handleInputChange={handleInputChange}
/>
);
}
}
})}
</TableBody>
</Table>
</TableContainer>
{props.hasPagination && (
<PaginationExtended
recordsPerPage={rowsPerPage}
className={"p-3 justify-content-end"}
totalRecords={rows.length}
paginate={handleChangePage}
currentPage={page}
shape={"round"}
/>
)}
</Paper>
);
};
export default ItemTable;
This function is called from a child component of the component at the top.
import React from "react";
import { TableCell, TableRow, Checkbox, TextField } from "#material-ui/core";
import objectInArray from "../../../helpers/objectInArray";
const ItemTableRow = (props) => {
return (
<TableRow key={props.index}>
{props.hasCheckbox && (
<TableCell padding="checkbox">
<Checkbox
id={props.row.id}
checked={objectInArray(
props.dynamicRows,
"id",
props.row.id.toString()
)}
onClick={props.handleCheckboxClick}
// inputProps={{
// "aria-labelledby": `${props.title}-${index}`,
// }}
/>
</TableCell>
)}
{props.headings.map((heading) => {
return (
<TableCell
className={"text-nowrap"}
id={`${props.title}-${props.index}`}
align="right"
>
{heading.isTextInput ? (
<TextField
onChange={props.handleInputChange}
id={`${props.title}-${heading.text}-${props.row.id}`}
type={heading.inputType}
size={"small"}
variant="outlined"
inputProps={{ min: 0 }}
notched={false}
InputLabelProps={{ shrink: false }}
className={`minInputWidth`}
InputProps={{
classes: { input: "py-2 customize-inputField" },
}}
name={heading.text.toLowerCase()}
placeholder={heading.text}
/>
) : (
<p>{props.row[heading.default]}</p>
)}
</TableCell>
);
})}
</TableRow>
);
};
export default ItemTableRow;
When I trigger this event the following error appears in the console.
Uncaught TypeError: props.setDynamicRows is not a function
The curious thing about this is that the handleCheckboxClick function does not throw any error and is also called called from the child component. I have tried reestructuring the components and functions but nothing works.
If someone knows what is happening I would really appreciate the help, thanks.

How to subtract only selected value from Array

Hello here is my problem, I have implemented a table that table fill when I choose some suggestion. The table contains three columns of (product, qty, balance and add button) So when I click add button it displays some popup form.
So I want to do when adding some quantity in the popup menu and after that click the add button it will reduce from the balance field in the table according to the selected product. Below is the table array.
import React, { useState } from "react"
import {
Grid,
Table,
TableContainer,
TableHead,
TableRow,
TableCell,
Paper,
TableBody,
Button
} from "#material-ui/core"
import AddItem from "./AddItem"
import { useStyles } from "../../../../styles/classes"
export default function ItemsList({
cart,
handleChange,
handleBlur,
values,
setFieldValue,
volumes
}) {
const [open, setOpen] = useState(false)
const [productId, setProductId] = useState("")
const [factoryId, setFactoryId] = useState("")
const handleClickOpen = (productId, factoryId) => {
setProductId(productId)
setFactoryId(factoryId)
setOpen(true)
}
const handleClose = (value) => {
setOpen(false)
}
const addToList = (factory) => {
setOpen(false)
const product = cart.find(
(item) => item.productId === Number(productId)
)
const item = {
productId: productId,
productName: product.productName,
containerNo: values.containerNo,
sealNo: values.sealNo,
qty: values.qty,
factoryId: factory.id,
factory: factory.name,
printDate: values.printDate,
printTime: values.printTime,
palletNo: values.palletNo,
}
const idx = values.volumes.findIndex(e=>e.number === Number(values.noOfContainers))
console.log(idx)
const current = values.volumes[idx].data;
current.push(item)
setFieldValue(`volumes[${idx}].data`,current)
//sum of qty in loaded volumes for this product
values.invoiceItems.forEach((item, idx) => {
item.balance = (Number(item.balance) - Number(values.qty))
})
setFieldValue('invoiceItems', values.invoiceItems)
}
const classes = useStyles()
return (
<Grid item md={12} sm={12} xs={12}>
<TableContainer component={Paper} >
<Table className={classes.table} size="small">
<TableHead>
<TableRow>
<TableCell align="left">Product</TableCell>
<TableCell align="left">Quantity</TableCell>
<TableCell align="left">Balance</TableCell>
<TableCell align="left">Add</TableCell>
</TableRow>
</TableHead>
<TableBody>
{cart.map((row, i) => (
<TableRow key={i}>
<TableCell align="left">{row.productName}</TableCell>
<TableCell align="left">{row.qty}</TableCell>
<TableCell align="left">{row.balance}</TableCell>
<TableCell align="left">
<Button
variant="outlined"
size="small"
color="secondary"
onClick={() => {
handleClickOpen(row.productId)
}}>
add
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
<AddItem
open={open}
onClose={handleClose}
handleChange={handleChange}
handleBlur={handleBlur}
values={values}
addToList={addToList}
volumes={volumes}
/>
</Grid>
)
}
import React, { useState} from "react"
import {
Grid,
Card,
CardContent,
CardActions,
Button,
CardHeader,
} from "#material-ui/core"
import Alert from "#material-ui/lab/Alert"
import axios from 'axios'
//validation
import { Formik, Form } from "formik"
import * as Yup from 'yup'
import { useStyles } from "../../../styles/classes"
import ItemList from "./subComponents/ItemsList"
import MetaData from "./subComponents/MetaData"
import ContainerList from "./subComponents/ContainerList"
import {useInitialValues} from '../../../hooks/useLoadingInfoData'
// validation schema
let validationSchema = Yup.object().shape({
volumes: Yup.string().required(),
})
export default function LoadingInfo(props) {
const classes = useStyles()
const [initialValues, setInitialValues] = useInitialValues()
const [volumes, setVolumes] = useState([])
const [alert, setAlert] = useState({
showAlert: false,
severity: "success",
message: "",
})
// create method
const submit = async (e, { resetForm }) => {
try {
await axios.post("/loadingInfo", e)
resetForm()
setAlert({
showAlert: true,
severity: "success",
message: "Loading Information created successfully!",
})
} catch (error){
if (error.response.status === 422) {
setAlert({
showAlert: true,
severity: 'error',
message: 'Loading information already exists!',
})
} else {
setAlert({
showAlert: true,
severity: 'error',
message: 'Loading information creation failed!',
})
}
}
}
return (
<Grid container className={classes.root} spacing={1}>
<Grid item xs={12} sm={12} md={12}>
<Formik
initialValues={initialValues}
onSubmit={submit}
validationSchema={validationSchema}
enableReinitialize>
{({
isValid,
dirty,
values,
handleChange,
handleBlur,
setFieldValue,
errors,
}) => {
return (
<Form>
<Card variant="outlined" style={{marginBottom: '1rem'}}>
<CardHeader title="Loading Information"></CardHeader>
<CardContent>
<Grid container spacing={1}>
<MetaData
values={values}
handleChange={handleChange}
handleBlur={handleBlur}
setAlert={setAlert}
setFieldValue={setFieldValue}
/>
<ItemList
cart={values.invoiceItems}
values={values}
handleChange={handleChange}
handleBlur={handleBlur}
setFieldValue={setFieldValue}
volumes={volumes}
/>
</Grid>
</CardContent>
</Card>
<Card variant="outlined">
<CardContent>
{values.volumes.map( (data , idx) =>
<ContainerList values={data} idx={idx} setFieldValue={setFieldValue}/>
)}
</CardContent>
<CardActions>
<Button
variant="contained"
color="primary"
type="submit"
disabled={!dirty || !isValid}>
create
</Button>
</CardActions>
</Card>
</Form>
)
}}
</Formik>
</Grid>
<Grid></Grid>
{alert.showAlert && (
<Grid item md={12}>
<Alert
severity={alert.severity}
onClose={() =>
setAlert({
...alert,
showAlert: false,
})
}>
{alert.message}
</Alert>
</Grid>
)}
</Grid>
)
}

Passing props within stateless functional components

I have the father which is Productos and a child called EditarProductos. I want to pass producto.id to EditarProductos.
Here is Productos:
import {Button, TableHead, TableRow, TableCell, TableBody, Table} from '#material-ui/core'
import { withStyles, makeStyles } from '#material-ui/core/styles';
import InsertarProductos from './InsertarProductos';
import Grid from '#material-ui/core/Grid';
import EditIcon from '#material-ui/icons/Edit';
import DeleteIcon from '#material-ui/icons/Delete';
import EditarProductos from './EditarProductos';
const StyledTableCell = withStyles((theme) => ({
head: {
backgroundColor: theme.palette.common.black,
color: theme.palette.common.white,
},
body: {
fontSize: 14,
},
}))(TableCell);
const StyledTableRow = withStyles((theme) => ({
root: {
'&:nth-of-type(odd)': {
backgroundColor: theme.palette.background.default,
},
},
}))(TableRow);
function Productos(props) {
const [productos, setProductos] = useState([]);
var id='';
useEffect(() => {
const getProductos = async () => {
const res = await fetch("/productos", {
method: 'GET',
headers: {'Content-Type': 'application/json'},
})
//console.log(res);
const response = await res.json();
setProductos(response);
}
getProductos();
})
function editar(producto){
console.log("entro 1");
//console.log(producto.id);
id = producto.id;
console.log(id);
return <EditarProductos productoEdit = {id}/>;
}
function eliminar(producto){
console.log(producto.id);
id=producto.id;
deleteProductos();
window.location.reload();
}
const deleteProductos = async () => {
console.log("entro");
console.log(id);
const res = await fetch("/productos", {
method: 'DELETE',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
id: id
})
})
const response = await res.json();
}
const useStyles = makeStyles({
table: {
minWidth: 700,
},
});
//console.log(plot);
const mystlye = {
minWidth: "50%",
minHeight: 50
};
//
const classes = useStyles();
return (
<div>
<br />
<Grid container spacing={3}>
<Grid item xs={3}></Grid>
<Grid item xs={3}></Grid>
<Grid item xs={3}></Grid>
<Grid item xs={3}>
<InsertarProductos productoInsert="fer"/>
</Grid>
</Grid>
<br />
<Table className={classes.table}>
<TableHead>
<TableRow>
<StyledTableCell>ID</StyledTableCell>
<StyledTableCell>Nombre</StyledTableCell>
<StyledTableCell>Precio de Compra</StyledTableCell>
<StyledTableCell>Precio de Venta</StyledTableCell>
<StyledTableCell>Cantidad</StyledTableCell>
<StyledTableCell>Categoria</StyledTableCell>
<StyledTableCell>Extras</StyledTableCell>
</TableRow>
</TableHead>
<TableBody>
{productos.map((producto) =>
<TableRow className="data-row">
<StyledTableCell>{producto.id}</StyledTableCell>
<StyledTableCell>{producto.nombre}</StyledTableCell>
<StyledTableCell>{producto.precio_compra}</StyledTableCell>
<StyledTableCell>{producto.precio_venta}</StyledTableCell>
<StyledTableCell>{producto.cantidad}</StyledTableCell>
<StyledTableCell>{producto.categorias_id}</StyledTableCell>
<StyledTableCell>
<Button variant="outlined" onClick={() => editar(producto)}>
<EditIcon />
</Button>
<Button variant="outlined" onClick={() => eliminar(producto)} ><DeleteIcon /> </Button>
</StyledTableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
);
}
export default Productos;
If I try to pass the id inside the button, it starts to print the id multiple times like in a loop.
EditarProductos is never reached and the id isn't passed. Could someone help me fix my problem, please?
PD: In EditarProductos I'm trying to print id like this:
console.log(props.productoEdit);
You can't return (and render) UI elements like this. You can rather set the id of a product to display though. Using the is you can conditionally render EditarProductos into the UI. You'll likely also want/need a way to reset this when the dialog is dismissed/closed.
The following is one way to do this:
function Productos(props) {
const [productos, setProductos] = useState([]);
const [id, setId] = useState(null); // create state variable
...
function editar(producto){
console.log("entro 1");
console.log(producto.id);
setId(producto.id);
}
function onEditarClose() {
setId(null);
}
...
return (
<div>
{id &&
// conditionally render in UI the dialog
<EditarProductos onClose={onEditarClose} productoEdit={id} />
}
<br />
<Grid container spacing={3}>
<Grid item xs={3}></Grid>
<Grid item xs={3}></Grid>
<Grid item xs={3}></Grid>
<Grid item xs={3}>
<InsertarProductos productoInsert="fer"/>
</Grid>
</Grid>
<br />
<Table className={classes.table}>
<TableHead>
<TableRow>
<StyledTableCell>ID</StyledTableCell>
<StyledTableCell>Nombre</StyledTableCell>
<StyledTableCell>Precio de Compra</StyledTableCell>
<StyledTableCell>Precio de Venta</StyledTableCell>
<StyledTableCell>Cantidad</StyledTableCell>
<StyledTableCell>Categoria</StyledTableCell>
<StyledTableCell>Extras</StyledTableCell>
</TableRow>
</TableHead>
<TableBody>
{productos.map((producto) =>
<TableRow className="data-row">
<StyledTableCell>{producto.id}</StyledTableCell>
<StyledTableCell>{producto.nombre}</StyledTableCell>
<StyledTableCell>{producto.precio_compra}</StyledTableCell>
<StyledTableCell>{producto.precio_venta}</StyledTableCell>
<StyledTableCell>{producto.cantidad}</StyledTableCell>
<StyledTableCell>{producto.categorias_id}</StyledTableCell>
<StyledTableCell>
<Button variant="outlined" onClick={() => editar(producto)}>
<EditIcon />
</Button>
<Button variant="outlined" onClick={() => eliminar(producto)} ><DeleteIcon /> </Button>
</StyledTableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
);
}

How to create checkbox in A React Function

I am trying to create a Checkbox to display and hide my React Table with some data in it. I have only used classes and am new to using Functions and as a result am struggling to implement a way to create a checkbox that can hide my React Table or a column.
import "react-table/react-table.css";
import React, { Component, useState, useEffect } from "react";
function dataquery() {
return fetch("www.website.com").then(response =>
response.json()
);
}
function Offence() {
const [count, setCount] = useState([]);
useEffect(() => {
dataquery().then(headlines => {
setCount(headlines);
});
}, []);
//event.preventDefault();
console.log(count.offences);
let data = [{}];
if (typeof count.offences !== "undefined" ) {
let newdata = count.offences.map(count => data.push({ name: count }));
// console.log("???");
}
console.log(typeof count.offence);
const columns = [
{
Header: "Name",
accessor: "name",
},
];
// trying to hide this react table or just hide the column
return <ReactTable data={data} columns={columns} filterable />;
}
export default Offence;
I am exporting this function into another file in which I render 'Offence'.
The fetch website is not the actual website as it needs a private login to work, so I replaced it with this placeholder for the purpose of this.
Thank you.
You can easily add an useState hook, which stores a boolean to show/not show the table. Then toggle this state when changing a checkbox. For example:
function Offence() {
// ... your component code
const [showTable, setShowTable] = useState(true);
// output
return (
<>
<input
type="checkbox"
checked={showTable}
onChange={() => { setShowTable(p => !p); }}
/>
{showTable ? <ReactTable ... /> : null}
</>
);
}
I have only used classes and am new to using Functions
In such a situation, I highly recommend to use materialui components. It would make your life much easier because you need not to step into gory details of styling anymore if you do not want to.
Below I roughly drafted a component which contains a table and a list of checkboxes for switching hide/show columns.
Hope it helps :)
import React, { useState, useEffect } from 'react'
import Grid from '#material-ui/core/Grid';
import Card from '#material-ui/core/Card';
import CardHeader from '#material-ui/core/CardHeader';
import CardContent from '#material-ui/core/CardContent';
import Table from '#material-ui/core/Table';
import TableBody from '#material-ui/core/TableBody';
import TableCell from '#material-ui/core/TableCell';
import TableHead from '#material-ui/core/TableHead';
import TableRow from '#material-ui/core/TableRow';
import FormControl from '#material-ui/core/FormControl';
import FormGroup from '#material-ui/core/FormGroup';
import FormControlLabel from '#material-ui/core/FormControlLabel'
import Checkbox from '#material-ui/core/Checkbox';
function App() {
const [showName, setshowName] = useState(true);
const [showQty, setshowQty] = useState(true);
const [showPrice, setshowPrice] = useState(true);
const dummydata = [{ name: "apple", qty: 12, price: 3.3 }, { name: "orange", qty: 3, price: 1.5 }, { name: "grape", qty: 10, price: 4.3 }]
return (
<Grid
container
direction="row"
justify="space-around"
alignItems="center"
>
<Grid item xs={12} sm={5}>
<Card>
<Table>
<TableHead>
<TableRow>
{showName ? <TableCell>Name</TableCell> : ""}
{showQty ? <TableCell >Qty.</TableCell> : ""}
{showPrice ? <TableCell >Price</TableCell> : ""}
</TableRow>
</TableHead>
<TableBody>
{dummydata.map(item => (
<TableRow>
{showName ? <TableCell component="th" scope="row" padding="none">
{item.name}
</TableCell> : ""}
{showQty ? <TableCell>{item.qty}</TableCell> : ""}
{showPrice ? <TableCell>{item.price}</TableCell> : ""}
</TableRow>
))}
</TableBody>
</Table>
</Card>
</Grid>
<Grid item xs={12} sm={5}>
<Card>
<CardHeader
title="Hide any column?"
/>
<CardContent>
<FormControl style={{ margin: 4 }}>
<FormGroup>
<FormControlLabel
control={
<Checkbox onChange={(e, checked) => setshowName(checked)} checked={showName} />
}
label="Hide Name"
/>
<FormControlLabel
control={
<Checkbox onChange={(e, checked) => setshowQty(checked)} checked={showQty} />
}
label="Hide Quantity"
/>
<FormControlLabel
control={
<Checkbox onChange={(e, checked) => setshowPrice(checked)} checked={showPrice} />
}
label="Hide Price"
/>
</FormGroup>
</FormControl>
</CardContent>
</Card>
</Grid>
</Grid>
);
}
export default App;

Categories