ReactJS - change attr value on click - javascript

I am developing a web app using the ReactJS framework.
I am trying to write an event that when I click on one element in a set it changes the value of the selected attribute to true and sets the remaining elements to false.
<NavigationButton to="/" label="Dashboard" exact>
<MenuItem className={classes.menuItem} selected={true/false}>
<ListItemIcon className={classes.icon}>
<Home />
</ListItemIcon>
<ListItemText classes={{ primary: classes.primary }} inset primary="Strona główna" />
</MenuItem>
</NavigationButton>
<NavigationButton to="/payment" label="Payment" exact>
<MenuItem className={classes.menuItem} selected={true/false}>
<ListItemIcon className={classes.icon}>
<Payment />
</ListItemIcon>
<ListItemText classes={{ primary: classes.primary }} inset primary="Moje płatności" />
</MenuItem>
</NavigationButton>
How do I do this?

I think the best way to do this is to encompasses all of your components in a stateful component that will track which of your elements is selected or not. This component will then have a function (something like handleClick) that will take in that press button class and setState changing to the element that should be selected now. Now you can pass down the function and the state (what is currently suppose to be selected) as props to the children elements and onClick on, it will trigger a callback to the parent component telling it to setState. Then in each of the individual components, you can just check to see if the prop this.props.currentSelect === ${name of the element} to see if they element should be selected or not
// some jsx file
class StatefulComponent extends React.Component{
constructor(props){
super(props);
this.state = {
currentlySelect: "someMenuItem"
}
this.handleClick = this.handleClick.bind(this);
}
handleClick(str){
this.setState({
currentlySelect: str
})
}
render(){
return(
<React.Fragment>
<NavigationButton to="/" label="Dashboard" exact>
<MenuItem handleClick={this.handleClick} currentlySelect={this.state.currentlySelect} className={classes.menuItem} selected={true / false}>
<ListItemIcon className={classes.icon}>
<Home />
</ListItemIcon>
<ListItemText classes={{ primary: classes.primary }} inset primary="Strona główna" />
</MenuItem>
</NavigationButton>
<NavigationButton to="/payment" label="Payment" exact>
<MenuItem handleClick={this.handleClick} currentlySelect={this.state.currentlySelect} className={classes.menuItem} selected={true / false}>
<ListItemIcon className={classes.icon}>
<Payment />
</ListItemIcon>
<ListItemText classes={{ primary: classes.primary }} inset primary="Moje płatności" />
</MenuItem>
</NavigationButton>
</React.Fragment>
)
}
}

Related

React Web page turning blank after adding a constant

I'm a React newbie and I was following a tutorial on YouTube, which is at the time of writing this approximately 3 months old.
I got to this phase:
However then I ran into a problem. This is a piece of code that works so far:
function App() {
const [theme, colorMode] = useMode();
return (
<ColorModeContext.Provider value={colorMode}>
<ThemeProvider theme={theme}>
<CssBaseline />
<div className='app'>
{/* <Sidebar /> This is the const which causes the web to break for some reason */}
<main className='content'>
<Topbar />
{/* <Routes> */}
{/* <Route path='/' element={<Dashboard />} /> */}
{/* <Route path='/classification' element={<Classification />} /> */}
{/* <Route path='/timetable' element={<Timetable />} /> */}
{/* <Route path='/class' element={<Class />} /> */}
{/* <Route path='/profile' element={<Profile />} /> */}
{/* <Route path='/settings' element={<Settings />} /> */}
{/* <Route path='/notifications' element={<Notifications />} /> */}
{/* <Route path='/calendar' element={<Calendar />} /> */}
{/* </Routes> */}
</main>
</div>
</ThemeProvider>
</ColorModeContext.Provider>
);
}
export default App;
However if I uncomment the <Sidebar /> the page turns blank. As far as I tried to debug, it doesn't matter if the Sidebar file is empty or not, the page turns blank regardless.
As a React newbie, my knowledge is very limited so I haven't tried much aside of debugging. All I know is that the code in the file doesn't affect the error in any way. What I expected to happen is a sidebar to appear on the left with a couple of buttons and an image. Instead the page just turned blank. I assume this is not caused by some outdated dependencies since as I said, the code in the Sidebar file doesn't seem to affect this error. My assumption is a logical mistake I can't manage to find.
I'd love to get any sort of help with this. Furthermore, if anyone knows how to write this piece of code differently, with the same functionality (you can see in the linked video tutorial above), I will definitely be looking forward to seeing your advice. Thanks a bunch!
EDIT: This is the Sidebar file:
import { useState } from "react";
import { ProSidebar, Menu, MenuItem } from "react-pro-sidebar";
import { Box, IconButton, Typography, useTheme } from "#mui/material";
import { Link } from "react-router-dom";
import "react-pro-sidebar/dist/css/styles.css";
import { tokens } from "../../theme";
import HomeOutlinedIcon from "#mui/icons-material/HomeOutlined";
import PeopleOutlinedIcon from "#mui/icons-material/PeopleOutlined";
import ContactsOutlinedIcon from "#mui/icons-material/ContactsOutlined";
import ReceiptOutlinedIcon from "#mui/icons-material/ReceiptOutlined";
import PersonOutlinedIcon from "#mui/icons-material/PersonOutlined";
import CalendarTodayOutlinedIcon from "#mui/icons-material/CalendarTodayOutlined";
import HelpOutlineOutlinedIcon from "#mui/icons-material/HelpOutlineOutlined";
import BarChartOutlinedIcon from "#mui/icons-material/BarChartOutlined";
import PieChartOutlineOutlinedIcon from "#mui/icons-material/PieChartOutlineOutlined";
import TimelineOutlinedIcon from "#mui/icons-material/TimelineOutlined";
import MenuOutlinedIcon from "#mui/icons-material/MenuOutlined";
import MapOutlinedIcon from "#mui/icons-material/MapOutlined";
const Item = ({ title, to, icon, selected, setSelected }) => {
const theme = useTheme();
const colors = tokens(theme.palette.mode);
return (
<MenuItem
active={selected === title}
style={{
color: colors.grey[100],
}}
onClick={() => setSelected(title)}
icon={icon}
>
<Typography>{title}</Typography>
<Link to={to} />
</MenuItem>
);
};
const Sidebar = () => {
const theme = useTheme();
const colors = tokens(theme.palette.mode);
const [isCollapsed, setIsCollapsed] = useState(false);
const [selected, setSelected] = useState("Dashboard");
return (
<Box
sx={{
"& .pro-sidebar-inner": {
background: `${colors.primary[400]} !important`,
},
"& .pro-icon-wrapper": {
backgroundColor: "transparent !important",
},
"& .pro-inner-item": {
padding: "5px 35px 5px 20px !important",
},
"& .pro-inner-item:hover": {
color: "#868dfb !important",
},
"& .pro-menu-item.active": {
color: "#6870fa !important",
},
}}
>
<ProSidebar collapsed={isCollapsed}>
<Menu iconShape="square">
{/* LOGO AND MENU ICON */}
<MenuItem
onClick={() => setIsCollapsed(!isCollapsed)}
icon={isCollapsed ? <MenuOutlinedIcon /> : undefined}
style={{
margin: "10px 0 20px 0",
color: colors.grey[100],
}}
>
{!isCollapsed && (
<Box
display="flex"
justifyContent="space-between"
alignItems="center"
ml="15px"
>
<Typography variant="h3" color={colors.grey[100]}>
Project Romeo
</Typography>
<IconButton onClick={() => setIsCollapsed(!isCollapsed)}>
<MenuOutlinedIcon />
</IconButton>
</Box>
)}
</MenuItem>
{!isCollapsed && (
<Box mb="25px">
<Box display="flex" justifyContent="center" alignItems="center">
<img
alt="profile-user"
width="100px"
height="100px"
src={`../../assets/user.png`} // Database here for user profile picture or default picture?
style={{ cursor: "pointer", borderRadius: "50%" }}
/>
</Box>
<Box textAlign="center">
<Typography
variant="h2"
color={colors.grey[100]}
fontWeight="bold"
sx={{ m: "10px 0 0 0" }}
>
Vojtěch Král
</Typography>
<Typography variant="h5" color={colors.greenAccent[500]}>
Project Romeo Developer
</Typography>
</Box>
</Box>
)}
<Box paddingLeft={isCollapsed ? undefined : "10%"}>
<Item
title="Dashboard"
to="/"
icon={<HomeOutlinedIcon />}
selected={selected}
setSelected={setSelected}
/>
<Typography
variant="h6"
color={colors.grey[300]}
sx={{ m: "15px 0 5px 20px" }}
>
Data
</Typography>
<Item
title="Manage Team"
to="/team"
icon={<PeopleOutlinedIcon />}
selected={selected}
setSelected={setSelected}
/>
<Item
title="Contacts Information"
to="/contacts"
icon={<ContactsOutlinedIcon />}
selected={selected}
setSelected={setSelected}
/>
<Item
title="Invoices Balances"
to="/invoices"
icon={<ReceiptOutlinedIcon />}
selected={selected}
setSelected={setSelected}
/>
<Typography
variant="h6"
color={colors.grey[300]}
sx={{ m: "15px 0 5px 20px" }}
>
Pages
</Typography>
<Item
title="Profile Form"
to="/form"
icon={<PersonOutlinedIcon />}
selected={selected}
setSelected={setSelected}
/>
<Item
title="Calendar"
to="/calendar"
icon={<CalendarTodayOutlinedIcon />}
selected={selected}
setSelected={setSelected}
/>
<Item
title="FAQ Page"
to="/faq"
icon={<HelpOutlineOutlinedIcon />}
selected={selected}
setSelected={setSelected}
/>
<Typography
variant="h6"
color={colors.grey[300]}
sx={{ m: "15px 0 5px 20px" }}
>
Charts
</Typography>
<Item
title="Bar Chart"
to="/bar"
icon={<BarChartOutlinedIcon />}
selected={selected}
setSelected={setSelected}
/>
<Item
title="Pie Chart"
to="/pie"
icon={<PieChartOutlineOutlinedIcon />}
selected={selected}
setSelected={setSelected}
/>
<Item
title="Line Chart"
to="/line"
icon={<TimelineOutlinedIcon />}
selected={selected}
setSelected={setSelected}
/>
<Item
title="Geography Chart"
to="/geography"
icon={<MapOutlinedIcon />}
selected={selected}
setSelected={setSelected}
/>
</Box>
</Menu>
</ProSidebar>
</Box>
);
};
export default Sidebar;

unable to set state in react for provided situation

i am building a ecommerce web app with react and i am unable to set state profileOptionsLayer when i click on the highlighted listitem both the logs are displayed on the console but component dosent rerender and state "profileOptionsLayer" is not updated either ,i am unable to locate the reason need help!
ALL imports .....
const TemporaryDrawer = ({
profileDrawerlayer,
setprofileDrawerlayer,
setuserDetails,
userDetails,
}) => {
const [profileOptionsLayer, setprofileOptionsLayer] = useState();
console.log(profileOptionsLayer);
return (
<>
<Drawer
anchor={"right"}
open={profileDrawerlayer}
onClose={() => {
setprofileDrawerlayer(false);
}}
>
<Box
sx={{ width: 250, background: "lightblue", height: "100%" }}
role="presentation"
onClick={() => {
setprofileDrawerlayer(false);
}}
onKeyDown={() => {
setprofileDrawerlayer(false);
}}
>
<List>
////////////////////////////////////// Below ///////////////////////////////////////////////
<ListItem disablePadding>
<ListItemButton
onClick={() => {
console.log("dsadsa");
setprofileOptionsLayer("View"); <= unable to set this state
console.log(profileOptionsLayer);
console.log("dsadsa");
}}
>
<ListItemIcon>
<VisibilityIcon />
</ListItemIcon>
<ListItemText primary={"View Profile"} />
</ListItemButton>
</ListItem>
/////////////////////////////////////// UP /////////////////////////////////////////
<ListItem
disablePadding
onClick={() => {
localStorage.removeItem("userId");
setuserDetails("");
}}
>
<ListItemButton>
<ListItemIcon>
<LogoutIcon />
</ListItemIcon>
<ListItemText primary={"Logout"} />
</ListItemButton>
</ListItem>
</List>
<Divider />
</Box>
</Drawer>
{profileOptionsLayer &&<ProfileOptions {...{ userDetails }} />}
</>
);
};
export default TemporaryDrawer;

In MUI how can i add color to something inside of CardHeader?

I would like to change the colors of each title={note.title} subheader={note.category} I have tried
const theme = createTheme ({
palette: {
category: {
color: blue
}
}
})
But that hasn't worked I have also tried inline
sx={{fontSize: 16,color: '#000000'}} again no luck.
How can I go about editing the color for those 2 sections?
<div>
<Card elevation={10} className={classes.test}>
<CardHeader
action={ // 200
<IconButton onClick={() => handleDelete(note.id)}>
<DeleteOutlined />
</IconButton>
}
title={note.title}
subheader={note.category}
/>
<CardContent>
<FormGroup>
<FormControlLabel sx={{fontSize: 16,color: '#000000'}} control={<Checkbox />} label={note.details} />
<FormControlLabel sx={{fontSize: 16,color: '#555555'}} control={<Checkbox />} label={note.details2} />
</FormGroup>
</CardContent>
</Card>
</div>
)
Full code here : https://github.com/Orelso/Project-notes
You can pass node in the title and subheader -
<CardHeader
action={ // 200
<IconButton onClick={() => handleDelete(note.id)}>
<DeleteOutlined />
</IconButton>
}
title={<span style={{fontSize: 16, color: "#000000"}}>{note.title}</span>}
subheader={<span style={{fontSize: 12, color: "#000000"}}>{note.category}</span>}
/>

Returning nightmare with .map() inside of a .map()

I've been at this for a while. So I have some nested navigation json that I am using. The top level navigation is loading fine (the nav.map) once I move further down the rabbit hole I find myself not returning the top level or the sub level navigation. Everything compiles successfully. Am I just missing it?
return(
<List component="nav" className={classes.root}>
{nav.map(function(element) {
<ListItem
button
onClick={handleClick}
id={element.toplevel}
key={element.toplevel}
>
<ListItemText primary={element.toplevel} />
{open ? <ExpandLess /> : <ExpandMore />}
</ListItem>;
return element.children.map(function(child) {
return (
<Collapse timeout="auto" unmountOnExit>
<List component="div" disablePadding>
<ListItem button className={classes.nested}>
<ListItemIcon>
<StarBorder />
</ListItemIcon>
<ListItemText primary={child.name} />
</ListItem>
</List>
</Collapse>
);
});
})}
</List>
);
Make sure that your map callback functions actually return the jsx code. Your return statements are not set right.
One way that is commonly used in react-land to make the jsx code more readable is the arrow function syntax. This way you get rid of the return statements and return the whole function body (it's just syntactic sugar).
Next thing: be aware of your closing tags. I just assumed that your list item of the element object closes after the ListItemText tag and that your second map function opens a new list item after your element ListItem. jsx only lets you return one root tag at a time. This is why (as the comment below has suggested) using an empty <> ... </> tag pair as a root element will solve this issue.
return (
<List component="nav" className={classes.root}>
{data.nav.map((element) => (
<>
<ListItem
button
onClick={handleClick}
id={element.toplevel}
key={element.toplevel}
>
<ListItemText primary={element.toplevel} />
{open ? <ExpandLess /> : <ExpandMore />}
</ListItem>
{
element.children.map((child) => (
<Collapse timeout="auto" unmountOnExit>
<List component="div" disablePadding>
<ListItem button className={classes.nested}>
<ListItemIcon>
<StarBorder />
</ListItemIcon>
<ListItemText primary={child.name} />
</ListItem>
</List>
</Collapse>
))
}
</>
))}
</List>
);
Sandbox link: https://codesandbox.io/s/material-demo-uv7c7?fontsize=14&hidenavigation=1&theme=dark
Try this, i have restructured it a bit.
<List component="nav" className={classes.root}>
{nav.map(function(element) {
return(
<ListItem
button
onClick={handleClick}
id={element.toplevel}
key={element.toplevel}
>
<ListItemText primary={element.toplevel} />
{open ? <ExpandLess /> : <ExpandMore />}
</ListItem>
{element.children.map(function(child) {
return (
<Collapse timeout="auto" unmountOnExit>
<List component="div" disablePadding>
<ListItem button className={classes.nested}>
<ListItemIcon>
<StarBorder />
</ListItemIcon>
<ListItemText primary={child.name} />
</ListItem>
</List>
</Collapse>
)
})
}
}))}
</List>
);

How to avoid DRY code with React Components

Currently Using React with Material UI v1.0 in implementing a list but I don't want to repeat my code.
The existing Code looks like this.
import List from 'material-ui/List';
import DashboardIcon from 'material-ui-icons/Dashboard';
import BuildIcon from 'material-ui-icons/Build';
import Listings from './BarComponents';
function SideBar() {
return (
<div>
<List>
<ListItem button>
<ListItemIcon>
<DashboardIcon />
</ListItemIcon>
<ListItemText primary="Dashboard" />
</ListItem>
<ListItem button>
<ListItemIcon>
<BuildIcon />
</ListItemIcon>
<ListItemText primary="Control Panel" />
</ListItem>
</List>
</div>
);
}
export default SideBar;
I want to get avoid repeating creating the list items so i've created a new file and passed the props into, code is below.
import React from 'react'
import { ListItem, ListItemIcon, ListItemText } from 'material-ui/List';
export default function Listings(props) {
return(
<div>
<ListItem button>
<ListItemIcon>
<props.icon />
</ListItemIcon>
<ListItemText primary={props.prim} />
</ListItem>
</div>
);
}
And also this
<Listings icon={DashboardIcon} prim="Dashboard" />
<Listings icon={BuildIcon} prim="Build" />
Into the original file for a replacement of
<ListItem button>
<ListItemIcon>
<DashboardIcon />
</ListItemIcon>
<ListItemText primary="Dashboard" />
</ListItem>
<ListItem button>
<ListItemIcon>
<BuildIcon />
</ListItemIcon>
<ListItemText primary="Control Panel" />
</ListItem>
Is the best way to pass a component e.g though
and call it via Thanks in advance.
You can use a dynamic component.
renderElement(name, props = {}) {
var MyComponent = name
return <MyComponent {...props} />;
}
render() {
return(
<div>
<ListItem v-for="item in list" key={item.id} button={item.button}>
<ListItemIcon>
{renderElement(props.icon)}
</ListItemIcon>
<ListItemText primary={props.prim} />
</ListItem>
</div>
);
}

Categories

Resources