React Material UI - DataGrid onRowClick - reactjs

I am completely new to React and Material UI. I had followed the step from YouTube to create DataGrid, but now I want to create one more function which when I click on a row of DataGrid, the interface will jump to the detail page of the row.
Thank you so much!!
`
import { Box } from "#mui/material";
import { DataGrid, GridToolbar } from "#mui/x-data-grid";
import { tokens } from "../../theme";
import { mockDatareworks } from "../../data/mockData";
import Header from "../../components/Header";
import { useTheme } from "#mui/material";
const Reworks = () => {
const theme = useTheme();
const colors = tokens(theme.palette.mode);
const columns = [
{ field: "id", headerName: "ID", flex: 0.5 },
{ field: "return_date", headerName: "Date" },
{
field: "customer_name",
headerName: "Customer",
flex: 1,
cellClassName: "name-column--cell",
},
{
field: "product_name",
headerName: 'Product',
flex: 1,
},
{
field: "rework_quantity",
headerName: "Quantity",
type: "number",
headerAlign: "left",
align: "left",
},
];
return (
<Box m="20px">
<Header
title="Rework"
subtitle="List of reworks for Future Reference"
/>
<Box
m="40px 0 0 0"
height="75vh"
sx={{
"& .MuiDataGrid-root": {
border: "none",
},
"& .MuiDataGrid-cell": {
borderBottom: "none",
},
"& .name-column--cell": {
color: colors.greenAccent[300],
},
"& .MuiDataGrid-columnHeaders": {
backgroundColor: colors.blueAccent[700],
borderBottom: "none",
},
"& .MuiDataGrid-virtualScroller": {
backgroundColor: colors.primary[400],
},
"& .MuiDataGrid-footerContainer": {
borderTop: "none",
backgroundColor: colors.blueAccent[700],
},
"& .MuiCheckbox-root": {
color: `${colors.greenAccent[200]} !important`,
},
"& .MuiDataGrid-toolbarContainer .MuiButton-text": {
color: `${colors.grey[100]} !important`,
},
}}
>
<DataGrid
rows={mockDatareworks}
columns={columns}
components={{ Toolbar: GridToolbar }}
/>
</Box>
</Box>
);
};
export default Reworks;
`
This is my current code for the DataGrid page, how can I add the function of clicking and jump to the detail page of the row?

Please use onRowClick prop
https://mui.com/x/react-data-grid/events/
<DataGrid
rows={mockDatareworks}
columns={columns}
components={{ Toolbar: GridToolbar }}
onRowClick={handleRowClick} // here
/>
Here are handleRowClick paras
const handleRowClick = (
params, // GridRowParams
event, // MuiEvent<React.MouseEvent<HTMLElement>>
details, // GridCallbackDetails
) => {
setMessage(params);
};

Related

React component not passing value to correct component

I have a simple React app that uses react-dnd to build a grid of draggable squares that have an initial color and text value and two components to change the color and change the text.
The color change (via ColorPicker2, using react-color library) works okay. The text change (using TextInput from #carbon/react) doesn't work as desired.
I thought I was applying the same logic with both components, but whilst the color-picker updates the color and retains that color when the square is moved, the text seems to render inside the TextInput and not the square itself and I can't figure out the logical difference.
The Code Sandbox is here: https://codesandbox.io/s/wild-waterfall-z8s1de?file=/src/App.js
This is the current code:
ColorPicker2.js
import "./styles.css";
import React from "react";
import { BlockPicker } from "react-color";
const presetColors = ["#9E9E9E", "#4CAF50", "#FFEB3B", "#F44336", "#2196F3"];
const ColorPicker2 = (props) => {
const handleChangeComplete = (color) => {
if (props.updateColor) {
props.updateColor(color.hex);
}
};
return (
<div className="palette">
<BlockPicker
className="palette"
colors={presetColors}
onChangeComplete={handleChangeComplete}
presetColors={Object.values(presetColors)}
color={props.currentColor}
/>
</div>
);
};
export default ColorPicker2;
App.js
import "./styles.css";
import React, { useState } from "react";
import { DndProvider, useDrag, useDrop } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend";
import edit from "./edit.svg";
import palette from "./palette.svg";
import ColorPicker2 from "./ColorPicker2";
import { TextInput } from "#carbon/react";
const DndWrapper = (props) => {
return <DndProvider backend={HTML5Backend}>{props.children}</DndProvider>;
};
const DraggableSquare = ({ index, text, color, moveSquare }) => {
const [{ isDragging }, drag] = useDrag({
type: "square",
item: { index },
collect: (monitor) => ({
isDragging: monitor.isDragging()
})
});
const [isHovered, setIsHovered] = useState(false);
const [, drop2] = useDrop({
accept: "square",
drop: (item, monitor) => {
const didDrop = monitor.didDrop();
if (!didDrop) {
moveSquare(item.index, index);
}
},
hover: (item, monitor) => {
setIsHovered(monitor.isOver());
},
collect: (monitor) => {
setIsHovered(monitor.isOver());
}
});
const [isPaletteOpen, setIsPaletteOpen] = useState(false);
const [isTextInputOpen, setIsTextInputOpen] = useState(false);
const [newText, setNewText] = useState(text);
const opacity = isDragging ? 0.5 : 1;
return (
<div className="square-div" ref={drop2}>
<div
className="grey-square"
ref={drag}
style={{
opacity,
backgroundColor: color,
width: "200px",
height: "200px",
textAlign: "center",
paddingTop: "30px",
position: "relative",
border: isHovered ? "3px solid blue" : "none",
borderRadius: "5px",
}}
onMouseOver={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
<img
src={edit}
onClick={() => {
setIsTextInputOpen(!isTextInputOpen);
if (!isTextInputOpen) {
moveSquare(index, newText, color, undefined);
}
}}
style={{
width: "15px",
height: "15px",
position: "absolute",
right: "5px",
top: "5px"
}}
alt="edit icon"
/>
{isTextInputOpen && (
<TextInput
id="newtext"
labelText=""
value={newText}
onChange={(e) => setNewText(e.target.value)}
/>
)}
<img
src={palette}
onClick={() => setIsPaletteOpen(!isPaletteOpen)}
style={{
width: "15px",
height: "15px",
position: "absolute",
right: "25px",
top: "5px"
}}
alt="palette icon"
/>
{isPaletteOpen && (
<ColorPicker2
className="palette"
currentColor={color}
updateColor={(newColor) =>
moveSquare(index, index, newText, newColor)
}
/>
)}
</div>
</div>
);
};
const Grid = () => {
const [grid, setGrid] = useState([
{ text: "1", color: "grey" },
{ text: "2", color: "grey" },
{ text: "3", color: "grey" },
{ text: "4", color: "grey" },
{ text: "5", color: "grey" },
{ text: "6", color: "grey" },
{ text: "7", color: "grey" },
{ text: "8", color: "grey" },
{ text: "9", color: "grey" },
{ text: "10", color: "grey" },
{ text: "11", color: "grey" },
{ text: "12", color: "grey" },
{ text: "13", color: "grey" },
{ text: "14", color: "grey" },
{ text: "15", color: "grey" }
]);
const moveSquare = (fromIndex, toIndex, newText, newColor) => {
setGrid((grid) => {
const newGrid = [...grid];
const item = newGrid[fromIndex];
newGrid.splice(fromIndex, 1);
newGrid.splice(toIndex, 0, {
text: newText || item.text,
color: newColor || item.color
});
return newGrid;
});
};
return (
<>
<DndWrapper>
<div
className="grid"
style={{
display: "grid",
gridTemplateColumns: "repeat(5, 190px)",
gridGap: "15px",
gridColumnGap: "20px",
gridRowGap: "10px",
position: "absolute"
}}
>
{grid.map((square, index) => (
<DraggableSquare
key={index}
index={index}
text={square.text}
color={square.color}
moveSquare={moveSquare}
//grid={grid}
//setGrid={setGrid}
/>
))}
</div>
</DndWrapper>
</>
);
};
export default Grid;
Any thoughts from fresh eyes would be helpful.
I think this is just a simple issue with using index as the key while mapping. Adjusting your code pen to have a unique key fixed it for me but the input text is not being saved anywhere so returned to the default text={square.text} when moved as expected.
Unique Id in objects:
const [grid, setGrid] = useState([
{ text: "1", color: "grey", id: crypto.randomUUID() },
{ text: "2", color: "grey", id: crypto.randomUUID() },
{ text: "3", color: "grey", id: crypto.randomUUID() },...])
Adding key to mapped object:
{grid.map((square, index) => (
<DraggableSquare
key={square.id}
index={index}
text={square.text}
color={square.color}
moveSquare={moveSquare}
//grid={grid}
//setGrid={setGrid}
/>}

How to style 'disabled' class in TextField in Material UI 5 using global CreateTheme?

I want to style differently TextFiled component , variant outlined once disabled={true}.
The way it was catched in material ui v.4 don't work in material ui v.5. I cannot also google the solution how to customize disabled version.
Below You can see how it was styled in material ui4 and it worked, not it does not.
export const MainTheme: Theme = createTheme({
components: {
MuiInputLabel: {
styleOverrides: {
root: {
fontSize: '13px',
'&$focused': {
borderColor: '#000',
},
'&$disabled': {
color: '#724a4a',
},
},
},
},
MuiInputBase: {
styleOverrides: {
root: {
'&$disabled': {
'& fieldset.MuiOutlinedInput-notchedOutline': {
borderColor: 'transparent',
background: 'rgb(0 0 0 / 4%)',
},
},
},
input: {
height: 'unset',
color: '#000000',
},
},
},
},
)}
You can do it like this SandBox
const finalTheme = createTheme({
components: {
MuiTextField: {
variants: [ // variants will help you define the props given by Mui and the styles you want to apply for it
{
props: { variant: 'outlined', disabled: true },
style: {
backgroundColor: 'green',
color: 'red',
fontSize: '5rem'
}
}
]
}
}
})
<ThemeProvider theme={finalTheme}>
<TextField
disabled
id="outlined-basic"
label="Outlined"
variant="outlined"
/>
</ThemeProvider>
Reference : https://mui.com/customization/theme-components/#global-style-overrides

Display selected row data in another component using Material UI/React JS

I am running into a bit of a problem grabbing data from a Data Grid (or XGrid) to display in another component on the page.
From the code below you can see that I am grabbing data from a local database that I am displaying in a Data Grid. What I want to do now is add the ability to take the selected rows and display the data (product ID, description, price, etc.) and display it in another component. Right now, I will settle for just a single selection.
I have tried many suggestions found here to add a onSelectionModelChange, but the only thing I am able to grab is the row id value. Not that it would make that much difference, but I am using MySQL for the backend.
Any suggestions?
Here's my React file:
import * as React from 'react';
import Axios from 'axios';
import { Grid } from '#material-ui/core';
import { createTheme } from '#material-ui/core/styles';
import { makeStyles } from '#material-ui/styles';
import { GridToolbarDensitySelector, GridToolbarFilterButton, XGrid } from '#material-ui/x-grid';
const currencyFormatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
});
const usdPrice = {
type: 'number',
width: 180,
valueFormatter: ({ value }) => currencyFormatter.format(Number(value)),
cellClassName: 'font-tabular-nums',
};
const defaultTheme = createTheme();
const useStyles = makeStyles(
(theme) => ({
root: {
padding: theme.spacing(0.5, 0.5, 0),
justifyContent: 'space-between',
display: 'flex',
alignItems: 'flex-start',
flexWrap: 'wrap',
background: '#f3f5f6'
},
textField: {
[theme.breakpoints.down('xs')]: {
width: '100%',
},
margin: theme.spacing(1, 0.5, 1.5),
'& .MuiSvgIcon-root': {
marginRight: theme.spacing(0.5),
},
'& .MuiInput-underline:before': {
borderBottom: `1px solid ${theme.palette.divider}`,
},
},
}),
{ defaultTheme },
);
function FilteringToolbar() {
const classes = useStyles();
return (
<div className={classes.root}>
<div>
<GridToolbarFilterButton />
<GridToolbarDensitySelector />
</div>
</div>
);
}
const ProductTable = () => {
const [rowData, setRowData] = React.useState([]);
const [rows, setRows] = React.useState(rowData);
React.useEffect(() => {
const axios = require('axios').default;
Axios.get("http://localhost:3001/api/get").then((response) => {
setRows(response.data);
}).catch(e => {
window.alert(e);
});
}, [rowData]);
const columns = [
{ field: 'prodID', headerName: 'Product ID', width: 130, disableReorder: true } ,
{ field: 'desc', headerName: 'Description', width: 200, editable: true, disableReorder: true },
{ field: 'price', headerName: 'Price', editable: true, disableReorder: true, ...usdPrice },
{ field: 'inStock', headerName: 'In Stock', width: 110, editable: true, disableReorder: true, headerAlign: 'center', align: 'center', type: 'boolean'},
{ field: 'new', headerName: 'New', width: 110, editable: true, disableReorder: true, headerAlign: 'center', align: 'center', type: 'boolean' },
]
return (
<Grid container item xs={12}>
<Grid container item xs={12}>
<Grid container item xs={3} />
<Grid container item xs={6} justifyContent="center" alignItems="center">
<div style={{ height: 500, width: '100%', display: 'block', marginLeft: 'auto', marginRight: 'auto' }}>
<XGrid checkboxSelection {...rows}
components={{ Toolbar: FilteringToolbar }}
rows={rows}
columns={columns}
id="id"
/>
</div>
</Grid>
<Grid container item xs={3} />
</Grid>
</Grid>
);
}
export default ProductTable;
I would suggest that instead of trying to get the row data that you need to pass to any child/related components from the table, you get the data directly from your own component's state. Since you already have the ids returned from onSelectionModelChange, you can simply use them to filter the rows state to get the selected items. For example:
...
const [selected, setSelected] = React.useState([]);
const [rows, setRows] = React.useState([]);
const handleSelectionChange = React.useCallback(
(selected = []) => {
setSelected(rows.filter(({ prodID }) => selected.includes(prodID)));
},
[rows]
);
...
<XGrid
// Calls our handler function that filters the selected items from state
onSelectionModelChange={handleSelectionChange}
checkboxSelection
{...rows}
components={{ Toolbar: FilteringToolbar }}
rows={rows}
columns={columns}
// Re-wires the grid to use your `prodID` instead of it's default `id`
getRowId={({ prodID }) => prodID}
/>
Working Code Sandbox: https://codesandbox.io/s/datagrid-selected-items-rm3f1?file=/src/App.tsx

Material Table rowStyle background color change based on cell value in

I am trying to have the color of the row change colors based on the priority number. For example, if the priority is 4 the color of the entire row should be blue. The problem is that I'm unsure of how to achieve this. I know Material Table assigns ID's to the rows, but I have no way of accessing them. Below is what I have come up with so far. I need options[backgroundColor] to be set based on the priority number. I have a codesandbox here as well https://codesandbox.io/s/notifications-material-ui-spq45
import React from "react";
import { Container } from "react-bootstrap";
import MaterialTable from "material-table";
import FilterListIcon from "#material-ui/icons/FilterList";
import SearchIcon from "#material-ui/icons/Search";
import FirstPage from "#material-ui/icons/FirstPage";
import LastPage from "#material-ui/icons/LastPage";
import ChevronLeft from "#material-ui/icons/ChevronLeft";
import ChevronRight from "#material-ui/icons/ChevronRight";
import CloseIcon from "#material-ui/icons/Close";
function App() {
//loop through the array of priority numbers, and display color based on number
function colors(num) {
for(let i = 0; i < num.length; i++) {
if (num[i] === 4) {
options.rowStyle.backgroundColor = "blue";
}
if (num[i] === 3) {
options.rowStyle.backgroundColor = "red";
}
console.log(num[i]);
}
}
let data = [
{
date: "06-29-2021",
subject: "CANBUS LOSS, Automatic Reboot!",
message:
"SCMs CANBUS LOSS for more than 15 min, Automatic System Reboot!",
category: "System",
priority: 4,
error: "SYS0080"
},
{
date: "06-28-2021",
subject: "Reboot!",
message: "Automatic System Reboot!",
category: "Alarm",
priority: 3,
error: "SYS0090"
},
{
date: "06-25-2021",
subject: "Testing!",
message: "Generator not running!",
category: "Generator",
priority: 2,
error: "SYS0050"
}
];
let columns = [
{ title: "Date", field: "date" },
{ title: "Subject", field: "subject" },
{ title: "Message", field: "message" },
{ title: "Category", field: "category" },
{ title: "Priority Level", field: "priority" },
{ title: "Error Code", field: "error" }
];
let options = {
filtering: false,
sorting: true,
rowStyle: {
fontFamily: "Mulish-Regular",
backgroundColor: ""
},
headerStyle: {
fontFamily: "Mulish-Regular",
fontSize: "1.1em",
fontWeight: "600",
backgroundColor: "#D1D1D8"
},
searchFieldStyle: {
fontFamily: "Mulish-Regular"
}
};
// Loop through all the data and find the priority number, and put it in an array
let map = data.map((x) => x.priority);
console.log(map);
colors(map);
return (
<>
<Container>
<MaterialTable
title=""
columns={columns}
data={data}
options={options}
icons={{
Filter: (props) => <FilterListIcon style={{ fill: "#2D3155 " }} />,
Search: (props) => <SearchIcon style={{ fill: "#2D3155 " }} />,
FirstPage: (props) => <FirstPage style={{ fill: "#2D3155 " }} />,
LastPage: (props) => <LastPage style={{ fill: "#2D3155 " }} />,
NextPage: (props) => <ChevronRight style={{ fill: "#2D3155 " }} />,
PreviousPage: (props) => (
<ChevronLeft style={{ fill: "#2D3155 " }} />
),
SortArrow: (props) => (
<FilterListIcon
style={{ fill: "#2D3155 ", fontSize: "1.4em", margin: ".4em" }}
/>
),
ResetSearch: (props) => <CloseIcon style={{ fill: "#2D3155 " }} />
}}
/>
</Container>
</>
);
}
export default App;
As you can read in the docs, rowStyle accepts an object or a function.
Hence, you can set rowStyle using a function that receives rowData as parameter, an example:
const rowBackgroundColors = {
"2": "yellow", // just for example, remove it if you don't need
"3": "orange",
"4": "red",
};
const options = {
// ...
rowStyle: (rowData) => {
return {
fontFamily: "Mulish-Regular",
backgroundColor: rowBackgroundColors[rowData.priority] ?? "#fff",
};
},
// ...
};

How to create dropdown list with description in React

I am trying to create a dropdown list with description in React. For reference you can see the image below:
Is there any other way using bootstrap or Material-UI so I can achieve this?
I am using react-select npm package for dropdown list. you can find live link and code below:
https://codesandbox.io/embed/react-select-selected-option-background-color-forked-jpu99?fontsize=14&hidenavigation=1&theme=dark
const colourOptions = [
{ value: "red", label: "Red" ,description:"Test description for red"},
{ value: "green", label: "Green", description:"Test description for green" },
{ value: "blue", label: "Blue", description:"Test description for blue" }
];
//for styling
const colourStyles = {
option: (styles, { data, isDisabled, isFocused, isSelected }) => {
// const color = chroma(data.color);
console.log({ data, isDisabled, isFocused, isSelected });
return {
...styles,
backgroundColor: isFocused ? "#00A3BE" : "#191D2F",
font: "Segoe UI",
color: "#F9FAFC"
};
}
};
export default () => (
<Select
defaultValue={colourOptions[1]}
label="Single select"
options={colourOptions}
styles={colourStyles}
/>
);
You can override the Option component and provide your own Option that can display both title and description:
import Select, { components } from "react-select";
const colourStyles = {
option: (styles, { data, isDisabled, isFocused, isSelected }) => {
return {
...styles,
backgroundColor: isFocused ? "#00A3BE" : "",
color: isFocused ? "#F9FAFC" : "#191D2F",
display: "flex",
paddingLeft: 0,
"& .left": {
display: "flex",
justifyContent: "center",
width: 60,
marginTop: 3
},
"& .right": {
width: "100%"
},
"& .right > .title": {
display: "block",
margin: "5px 0"
}
};
}
};
const Option = (props) => {
return (
<components.Option {...props}>
<div className="left">{props.isSelected ? "✔" : ""}</div>
<div className="right">
<strong className="title">{props.data.label}</strong>
<div>{props.data.description}</div>
</div>
</components.Option>
);
};
export default () => (
<Select
defaultValue={colourOptions[1]}
label="Single select"
options={colourOptions}
styles={colourStyles}
components={{ Option }}
/>
);
Live Demo

Resources