react material-table onrowadd fails - reactjs

I am trying to add a row in a material-table and am getting an error
The example mentioned is in the material tables docs
package.json
"dependencies": {
"#material-ui/core": "^4.1.0",
"#material-ui/icons": "^4.1.0",
"classnames": "^2.2.6",
"material-table": "^1.39.0",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-router-dom": "^5.0.1",
"react-scripts": "3.0.1"
},
testingList.js
<div className={classes.root}>
<MaterialTable
title="Testing"
icons={tableIcons}
columns={this.state.columns}
data={this.state.data}
editable={{
onRowAdd: (newData) =>
new Promise((resolve, reject) => {
setTimeout(() => {
{
const data = this.state.data
data.push(newData)
this.setState({ data }, () => resolve())
}
resolve()
}, 1000)
}),
}}
/>
</div>
Error:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
Check the render method of MTableAction.
If I remove on add method the function works as expected.
Also it works fine if I remove the line icons={tableIcons} where tableIcons is
const tableIcons = {
FirstPage: FirstPage,
LastPage: LastPage,
NextPage: ChevronRight,
PreviousPage: ChevronLeft,
};

import React, { useState, useEffect } from 'react';
import Search from "#material-ui/icons/Search";
import ViewColumn from "#material-ui/icons/ViewColumn";
import SaveAlt from "#material-ui/icons/SaveAlt";
import ChevronLeft from "#material-ui/icons/ChevronLeft";
import ChevronRight from "#material-ui/icons/ChevronRight";
import FirstPage from "#material-ui/icons/FirstPage";
import LastPage from "#material-ui/icons/LastPage";
import Add from "#material-ui/icons/Add";
import Check from "#material-ui/icons/Check";
import FilterList from "#material-ui/icons/FilterList";
import Remove from "#material-ui/icons/Remove";
import ArrowDownward from "#material-ui/icons/ArrowDownward";
import Clear from "#material-ui/icons/Clear";
import DeleteOutline from "#material-ui/icons/DeleteOutline";
import Edit from "#material-ui/icons/Edit";
import MaterialTable from "material-table";
import UserService from "../../services/user.service";
import ToastServive from "react-material-toast";
import userService from '../../services/user.service';
var _table_Data = [];
const toast = ToastServive.new({
place: "topRight",
duration: 2,
maxCount: 8,
});
const server_Data = userService._get_data().then((response) => {
return response.data.data
})
export default function InputTable(props) {
useEffect(() => {
UserService._get_data().then((response) => {
const dataUpdate = [...response.data.data];
setData([...dataUpdate]);
})
})
const [columns] = useState([
{
title: "Name",
field: "Name",
cellStyle: {
width: "15%",
maxWidth: "15%",
fontSize: 12,
},
headerStyle: {
width: "15%",
maxWidth: "15%",
},
},
{
title: "Exposure",
field: "EAD",
cellStyle: {
width: "20%",
maxWidth: "20%",
fontSize: 12,
textAlign: "left",
},
headerStyle: {
width: "20%",
maxWidth: "20%",
textAlign: "left",
},
},
{
title: "Def. Prob.",
field: "PD",
cellStyle: {
width: "25%",
maxWidth: "25%",
fontSize: 12,
textAlign: "left",
},
headerStyle: {
width: "25%",
maxWidth: "25%",
textAlign: "left",
},
},
{
title: "LGD",
field: "LGD",
cellStyle: {
width: "30px",
maxWidth: "30px",
fontSize: 12,
textAlign: "left",
},
headerStyle: {
width: 20,
maxWidth: 12,
textAlign: "left",
},
},
{
title: "Corr",
field: "w",
cellStyle: {
width: 20,
maxWidth: 20,
fontSize: 12,
textAlign: "left",
},
},
]);
const [data, setData] = useState(_table_Data);
return (
<div
style={{
fontSize: 10,
maxWidth: "100%",
margin: "auto",
padding: "0 0",
}}
>
<MaterialTable
icons={{
Check: Check,
DetailPanel: ChevronRight,
Delete: DeleteOutline,
Export: SaveAlt,
Filter: FilterList,
FirstPage: FirstPage,
LastPage: LastPage,
NextPage: ChevronRight,
PreviousPage: ChevronLeft,
Search: Search,
ThirdStateCheck: Remove,
Add: Add,
SortArrow: ArrowDownward,
Clear: Clear,
Edit: Edit,
ViewColumn: ViewColumn,
ResetSearch: Clear,
}}
options={{
actionsColumnIndex: -1,
headerStyle: {
fontSize: 12,
fontWeight: "bold",
backgroundColor: "white",
color: "black",
},
rowStyle: {
color: "black",
backgroundColor: "#eeeeee",
height: "50px",
},
actionsCellStyle: {
fontSize: "small", //doesn't work
},
showTitle: true,
search: true,
padding: "dense",
exportButton: true,
}}
title="Editable Preview"
columns={columns}
data={data}
editable={{
onBulkEditRow: (changes) => {
console.log(changes);
},
onBulkUpdate: (changes) =>
new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 1000);
}),
onRowAddCancelled: (rowData) => console.log("Row adding cancelled"),
onRowUpdateCancelled: (rowData) =>
console.log("Row editing cancelled"),
onRowAdd: (newData) =>
new Promise((resolve, reject) => {
setTimeout(() => {
const _sendData = newData;
UserService.datamanage(_sendData).then((response) => {
toast.success(JSON.parse(JSON.stringify(response.data.message)));
}).catch(() => {
toast.error("failed")
})
resolve();
}, 1000);
}),
onRowUpdate: (newData, oldData) =>
new Promise((resolve, reject) => {
setTimeout(() => {
const dataUpdate = [...data];
const index = oldData.tableData.id;
dataUpdate[index] = newData;
setData([...dataUpdate]);
resolve();
}, 1000);
}),
onRowDelete: (oldData) =>
new Promise((resolve, reject) => {
setTimeout(() => {
const dataDelete = [...data];
const index = oldData.tableData.id;
dataDelete.splice(index, 1);
setData([...dataDelete]);
resolve();
}, 1000);
}),
}}
/>
</div>
);
}

I had the same issue and I solved it by adding Actions under components so that the code becomes:
<Table
title="Editable Preview"
columns={this.state.columns}
data={this.state.data}
editable={{
isEditable: rowData => rowData.name === "a", // only name(a) rows would be editable
isDeletable: rowData => rowData.name === "b", // only name(a) rows would be deletable
onRowAdd: newData => new Promise((resolve) => console.log("onrowadd", newData)),
onRowUpdate: (newData, oldData) => new Promise((resolve) => console.log("onRowUpdate", newData, oldData)),
onRowDelete: (oldData) => new Promise((resolve) => console.log("onRowDelete", oldData)),
}}
components={{
Actions: props => (
<div>
<IconButton
onClick={() =>
this.props.history.push(`/teams/${props.data.uuid}`)
}
>
<EditIcon />
</IconButton>
<IconButton
onClick={() =>
this.props.history.push(`/teams/${props.data.uuid}`)
}
>
<EditIcon />
</IconButton>
</div>
)
}}
/>
Hope this helps!

I solved it by downgrading to version 1.54.0

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}
/>}

Putting two functions in the same "onclick"

I'm trying to display a group of users in a table, and I'm using a library called "ReactTable", and I have an "approve" button, when the user clicks on the "approve" button two things should happen:
The first will be a dispatch of the approveUser function
The second thing, a message will appear that "acceptance has been completed".
The problem is that I want to put two functions in the same button and the same "onClick", and when I did that the site was no longer working,
How can I solve the problem?
function Alert(props) {
return <MuiAlert elevation={6} variant="filled" {...props} />;
}
const useStyles = makeStyles({
button1: {
backgroundColor: "none",
"&:hover": {
backgroundColor: "#43a047",
color: "#e8e4e4",
transition: "0.3s",
borderColor: "#43a047",
},
},
button2: {
backgroundColor: "none",
"&:hover": {
backgroundColor: "#e53935",
color: "#e8e4e4",
transition: "0.3s",
borderColor: "#e53935",
},
},
});
function ContactsList(props) {
const classes = useStyles();
const dispatch = useDispatch();
const [open, setOpen] = React.useState(false);
const handleClick = () => {
setOpen(true);
};
const handleClose = (event, reason) => {
if (reason === "clickaway") {
return;
}
setOpen(false);
};
useEffect(() => {
dispatch(getUsersRequests());
}, [dispatch]);
const usersRequestsState = useSelector(
(state) => state.usersRequestsApp["usersRequests"]
);
console.log(
"requests inside Contacts List: ",
usersRequestsState["usersRequests"]
);
const columns = useMemo(
() => [
{
Header: "",
// this is function or property
accessor: "avatar",
Cell: ({ row }) => {
return (
<Avatar
className="mx-8"
alt={row.original.name}
src={row.original.avatar}
style={{ height: "7rem", width: "7rem" }}
/>
);
},
className: "justify-center",
width: 64,
sortable: false,
},
{
Header: "First Name",
accessor: "firstName",
className: "font-medium",
sortable: true,
},
{
Header: "Last Name",
accessor: "lastName",
className: "font-medium",
sortable: true,
},
{
Header: "Email",
accessor: "email",
sortable: true,
},
{
Header: "Phone Number",
accessor: "phoneNumber",
sortable: true,
},
{
Header: "actions",
accessor: "",
sortable: true,
id: "action",
// width: 100,
Cell: ({ row }) => (
<div className="flex items-center">
<ButtonGroup
style={{
maxWidth: "206px",
maxHeight: "40px",
minWidth: "206px",
minHeight: "40px",
}}
aria-label="outlined primary button group"
>
<Button
style={{
maxWidth: "100px",
minWidth: "100px",
}}
onClick={(ev) => {
ev.stopPropagation();
handleClick;
dispatch(approveUser(row.original.id));
}}
className={classes.button1}
>
approve
</Button>
<Snackbar
open={open}
autoHideDuration={6000}
onClose={handleClose}
>
<Alert onClose={handleClose} severity="success">
acceptance has been completed!
</Alert>
</Snackbar>
<Button
style={{
maxWidth: "100px",
minWidth: "100px",
}}
onClick={(ev) => {
ev.stopPropagation();
dispatch(rejectUser(row.original.id));
}}
className={classes.button2}
>
reject
</Button>
</ButtonGroup>
</div>
),
},
],
[]
);
const dataResponse = useMemo(() => usersRequestsState["data"]);
console.log("dataResponse: ", dataResponse);
return (
<motion.div
initial={{ y: 20, opacity: 0 }}
animate={{ y: 0, opacity: 1, transition: { delay: 0.2 } }}
>
<ContactsTable columns={columns} data={dataResponse} />
</motion.div>
);
}
export default ContactsList;
There is no use of just putting a function reference and not using it
onClick={(ev) => {
ev.stopPropagation();
handleClick;
dispatch(approveUser(row.original.id));
}}
You should invoke the function by putting () at the end of the handleClick as:
onClick={(ev) => {
ev.stopPropagation();
handleClick(ev); // INVOCATION
dispatch(approveUser(row.original.id));
}}
This is just personal preference
You are handling onClick inline and trying to invoke the function handleClick, so It would be much cleaner if you could just set the state of Open inside the handler.
setOpen(true);
Below code is much more readable
onClick={(ev) => {
ev.stopPropagation();
setOpen(true);
dispatch(approveUser(row.original.id));
}}
When you call the function you need to use ()
onClick={(ev) => {
ev.stopPropagation();
handleClick();
dispatch(approveUser(row.original.id));
}}

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",
};
},
// ...
};

Logo not showing in AppBar (Material UI / React)

The logo is not showing on my AppBar for some reason. Here's what I am getting:
This is my code:
import {
AppBar,
Toolbar,
Typography,
makeStyles,
Button,
IconButton,
Drawer,
Link,
MenuItem,
} from "#material-ui/core";
import MenuIcon from "#material-ui/icons/Menu";
import React, { useState, useEffect } from "react";
import { Link as RouterLink } from "react-router-dom";
import logo from '../overland-ninja-logo.png';
const headersData = [
{
label: "Listings",
href: "/listings",
},
{
label: "Mentors",
href: "/mentors",
},
{
label: "My Account",
href: "/account",
},
{
label: "Log Out",
href: "/logout",
},
];
const useStyles = makeStyles(() => ({
header: {
backgroundColor: "#400CCC",
paddingRight: "79px",
paddingLeft: "118px",
"#media (max-width: 900px)": {
paddingLeft: 0,
},
},
logo: {
fontFamily: "Work Sans, sans-serif",
fontWeight: 600,
color: "#FFFEFE",
textAlign: "left",
},
menuButton: {
fontFamily: "Open Sans, sans-serif",
fontWeight: 700,
size: "18px",
marginLeft: "38px",
},
toolbar: {
display: "flex",
justifyContent: "space-between",
},
drawerContainer: {
padding: "20px 30px",
},
}));
export default function Header() {
const { header, logo, menuButton, toolbar, drawerContainer } = useStyles();
const [state, setState] = useState({
mobileView: false,
drawerOpen: false,
});
const { mobileView, drawerOpen } = state;
useEffect(() => {
const setResponsiveness = () => {
return window.innerWidth < 900
? setState((prevState) => ({ ...prevState, mobileView: true }))
: setState((prevState) => ({ ...prevState, mobileView: false }));
};
setResponsiveness();
window.addEventListener("resize", () => setResponsiveness());
}, []);
const displayDesktop = () => {
return (
<Toolbar className={toolbar}>
{femmecubatorLogo}
<div>{getMenuButtons()}</div>
</Toolbar>
);
};
const displayMobile = () => {
const handleDrawerOpen = () =>
setState((prevState) => ({ ...prevState, drawerOpen: true }));
const handleDrawerClose = () =>
setState((prevState) => ({ ...prevState, drawerOpen: false }));
return (
<Toolbar>
<IconButton
{...{
edge: "start",
color: "inherit",
"aria-label": "menu",
"aria-haspopup": "true",
onClick: handleDrawerOpen,
}}
>
<MenuIcon />
</IconButton>
<Drawer
{...{
anchor: "left",
open: drawerOpen,
onClose: handleDrawerClose,
}}
>
<div className={drawerContainer}>{getDrawerChoices()}</div>
</Drawer>
<div>{femmecubatorLogo}</div>
</Toolbar>
);
};
const getDrawerChoices = () => {
return headersData.map(({ label, href }) => {
return (
<Link
{...{
component: RouterLink,
to: href,
color: "inherit",
style: { textDecoration: "none" },
key: label,
}}
>
<MenuItem>{label}</MenuItem>
</Link>
);
});
};
const femmecubatorLogo = (
<img src={logo} />
);
const getMenuButtons = () => {
return headersData.map(({ label, href }) => {
return (
<Button
{...{
key: label,
color: "inherit",
to: href,
component: RouterLink,
className: menuButton,
}}
>
{label}
</Button>
);
});
};
return (
<header>
<AppBar className={header}>
{mobileView ? displayMobile() : displayDesktop()}
</AppBar>
</header>
);
}
I am quite new to react and I am sort of confused about how to go about this. I have tried all the tutorials but can't find the right solution. Any help would be much appreciated.
You are reassigning the value of logo after importing the image.
import logo from "../overland-ninja-logo.png"; // value of logo is correctly assigned to a path to the image
...
const useStyles = makeStyles(() => ({
logo: {
fontFamily: "Work Sans, sans-serif",
fontWeight: 600,
color: "#FFFEFE",
textAlign: "left"
},
}));
...
const { header, logo, menuButton, toolbar, drawerContainer } = useStyles(); // value of logo is incorrectly assigned to a an object
If you are using vscode, you should get a typescript warning at import logo:
'logo' is declared but its value is never read.ts(6133)

How to add "plus-button" on top right in material-table for react and call my specific function in react

This is my code:
import React, { useState, useEffect } from 'react';
import { Fade } from "#material-ui/core";
import MaterialTable from 'material-table';
import { makeStyles } from '#material-ui/core/styles';
import './styles.css';
const useStyles = makeStyles(theme => ({
root: {
flexGrow: 1,
width: '70%',
margin: 'auto',
marginTop: 20,
boxShadow: '0px 0px 8px 0px rgba(0,0,0,0.4)'
}
}));
function User(props) {
const classes = useStyles();
const [checked, setChecked] = React.useState(false);
useEffect(() => {
setChecked(prev => !prev);
}, [])
const [state, setState] = React.useState({
columns: [
{ title: 'name', field: 'name' },
{ title: 'Setor', field: 'sector' }
],
data: [
{ name: 'Tom Brady', setor: 'Quarterback'},
{ name: 'Aaron Rodgers', setor: 'Quarterback'},
{ name: 'Ryan Tannehill', setor: 'Quarterback'},
{ name: 'Julian Edelman', setor: 'Wide Receiver'},
{ name: 'Julio Jones', setor: 'Wide Receiver'},
{ name: 'Marcus Mariota', setor: 'Quarterback'},
{ name: 'Patrick Mahomes', setor: 'Quarterback'},
{ name: 'Antonio Brown', setor: 'Wide Receiver'},
{ name: 'Eli Manning', setor: 'Quarterback'},
{ name: 'Antonio Brown', setor: 'Wide Receiver'},
{ name: 'Mike Evans', setor: 'Wide Receiver'},
{ name: 'Russel Wilson', setor: 'Quarterback'},
{ name: 'Drew Brees', setor: 'Quarterback'},
{ name: 'Cam Newton', setor: 'Quarterback'}
],
actions: [
{ icon: 'create', tooltip: 'Edit', onClick: (event, rowData) => alert('Edit ' + rowData.name + '?')},
{ icon: 'lock', tooltip: 'Block', onClick: (event, rowData) => alert('Block ' + rowData.name + '?')},
{ icon: 'delete', tooltip: 'Delete', onClick: (event, rowData) => alert('Delete ' + rowData.name + '?')}
],
options: {
headerStyle: { color: 'rgba(0, 0, 0, 0.54)' },
actionsColumnIndex: -1,
exportButton: true,
paging: true,
pageSize: 10,
pageSizeOptions: [],
paginationType: 'normal'
}
});
return (
<>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<Fade in={checked} style={{ transitionDelay: checked ? '300ms' : '0ms' }}>
<div className={classes.root}>
<MaterialTable options={state.options} title="Users" columns={state.columns} data={state.data} actions={state.actions}></MaterialTable>
</div>
</Fade>
</>
);
}
export default User;
I wanna add this button:
If I follow the default code from here https://material-ui.com/pt/components/tables/, I must add this code:
editable={{
onRowAdd: newData =>
new Promise(resolve => {
setTimeout(() => {
resolve();
setState(prevState => {
const data = [...prevState.data];
data.push(newData);
return { ...prevState, data };
});
}, 600);
}),
But this code calls a specific function for material-table, I wanna call my own function, how can I add the previous button and call my own function?
My own function will open a modal with some inputs, more inputs than I show on table.
You can create custom actions
<MaterialTable
title="Editable Example"
columns={state.columns}
data={state.data}
actions={[
{
icon: "add_box",
tooltip: "my tooltip",
position: "toolbar",
onClick: () => {
console.log("clicked");
}
}
]}
/>
Working demo: https://codesandbox.io/s/material-demo-mgh26
You can override the toolbar, adding your custom button (or some other content!), as explained at https://stackoverflow.com/a/69854673/1288109 :
<MaterialTable
components={{
Toolbar: (props) => (
<div
style={{
display: "flex",
justifyContent: "flex-end",
alignItems: "center"
}}
>
<div style={{ width: "13rem" }}>
<MTableToolbar {...props} />
</div>
<Tooltip title="Add">
<IconButton>
<AddBox />
</IconButton>
</Tooltip>
</div>
),
}}
/>
You can use the position or isFreeAction property for having the action displayed there.
<MaterialTable
title="Editable Example"
columns={state.columns}
data={state.data}
actions={[
{
icon: "add_box",
tooltip: "my tooltip",
isFreeAction: true,
onClick: () => {
console.log("clicked");
}
}
]}
/>
The position parameter is more flexible providing different placements for the Button.
isFreeAction in the other hand accepts just a boolean for the action type.
Sandbox cloned from Mosh Feu https://codesandbox.io/s/material-demo-m8eug

Resources