How to link or route the react semantic UI dropdown component - javascript

I am a newbie to React. I am trying to add links to the React semantic UI dropdown menu. Following is the component that I fetched from React semantic UI
import React from "react";
import { Dropdown } from "semantic-ui-react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
const trigger = (
<span style={{ marginTop: "2px" }}>
<i aria-hidden="true" class="user big icon" size="big" />
</span>
);
const options = [
{ key: "user", text: "Account", icon: "user", to: "/accounts" },
{ key: "settings", text: "Settings", icon: "settings", to: "/settings" },
{ key: "sign-out", text: "Sign Out", icon: "sign out", to: "/sign-out" }
];
const DropdownMenu = () => (
<Dropdown
trigger={trigger}
options={options}
pointing="top right"
icon={null}
/>
);
export default DropdownMenu;
I tried adding "to" keyword to the options array and have added the Route paths to the Router which lies in a different component but it's not working. Any help would be appreciated, Thank you.

Or you can use Dropdown.Menu and Dropdown.Item. Each Dropdown.Item can have param as={Link} to='/somewhere'/.
import React from "react";
import { Dropdown } from "semantic-ui-react";
import { Link } from "react-router-dom";
const trigger = (
<span style={{ marginTop: "2px" }}>
<i aria-hidden="true" class="user big icon" size="big" />
</span>
);
const DropdownMenu = () => (
<Dropdown trigger={trigger} pointing='top left' icon={null}>
<Dropdown.Menu>
<Dropdown.Item text='Account' icon='user' as={Link} to='/accounts'/>
<Dropdown.Item text='Settings' icon='settings' as={Link} to='/settings'/>
<Dropdown.Item text='Sign Out' icon='sign out' as={Link} to='/sign-out'/>
</Dropdown.Menu>
</Dropdown>
);
export default DropdownMenu;
I hope it will help you.

You can try something like this. change the key to to value in you options array. then use onChange method to handle the selection. You may want to pass the history prop from parent component down to the component you want to invoke the action if its not available.
import React, { Component } from "react";
import ReactDOM from "react-dom";
import { Dropdown, Form } from "semantic-ui-react";
const trigger = (
<span style={{ marginTop: "2px" }}>
<i aria-hidden="true" class="user big icon" size="big" />
</span>
);
const options = [
{ key: "user", text: "Account", icon: "user", value: "/accounts" },
{ key: "settings", text: "Settings", icon: "settings", value: "/settings" },
{ key: "sign-out", text: "Sign Out", icon: "sign out", value: "/sign-out" }
];
class App extends Component {
move = (e, { value }) => {
this.props.history.push('value')
}
render() {
return (
<div>
<Dropdown
options={options}
trigger={trigger}
icon={null}
onChange={this.move}
/>
</div>
);
}
}

My solution based on the answer from Jan Fara:
import React from 'react';
import { Dropdown } from 'semantic-ui-react';
import Avatar from 'react-avatar';
import { Link } from 'react-router-dom';
function DropdownuserMenu() {
const trigger = (
<span>
<Avatar name='Happy User' size="40"/>
</span>
);
return (
<Dropdown trigger={trigger} pointing='top left' icon={null}>
<Dropdown.Menu>
<Dropdown.Item text='Account' icon='user' as={Link} to='/accounts'/>
<Dropdown.Item text='Settings' icon='settings' as={Link} to='/settings'/>
<Dropdown.Item text='Sign Out' icon='sign out' as={Link} to='/sign-out'/>
</Dropdown.Menu>
</Dropdown>
);
}
export default DropdownuserMenu;

Related

Navigate from card to another page

I am building a React App and want to navigate to another page by "clicking on the card" to display information about that place.
This is my App.js
import React from "react";
// import NavBar from "./NavBar";
import DestCard from "./Card";
import { Grid } from "#mui/material";
// import MidPage from "./Midpage";
const cardInfo = [
{
image: "https://cdn.myanimelist.net/images/characters/11/174517.jpg",
title: "Lebron James",
text: "THE GOAT",
},
{
image: "https://upload.wikimedia.org/wikipedia/commons/a/aa/TechCrunch_Disrupt_2019_%2848834853256%29_%281%29.jpg",
title: "Stephen Curry",
text: "3 pointer GOD",
},
{
image: "https://upload.wikimedia.org/wikipedia/commons/b/bf/LeBron_James_-_51959723161_%28cropped%29.jpg",
title: "Lebron James",
text: "THE GOAT",
},
{
image: "https://upload.wikimedia.org/wikipedia/commons/a/aa/TechCrunch_Disrupt_2019_%2848834853256%29_%281%29.jpg",
title: "Stephen Curry",
text: "3 pointer GOD",
}
];
function App() {
return (
<div>
<Grid container spacing={{ xs: 1}} columns={{ xs: 4, md:12}}>
{cardInfo.map((details, index) => (
<Grid item xs={2} sm={4} md={4} key={index}>
<DestCard details= {details} />
</Grid>
))}
</Grid>
</div>
)
}
export default App;
Here I have the Card in the grid.
Next is the Card.js
import * as React from 'react';
import {
StyledCard,
CardImage,
CardTextWrapper,
CardTitle
} from './Card.style.js';
function DestCard({ details }) {
// console.log(details.image);
return (
<StyledCard>
<CardImage bg= {details.image}>
<CardTextWrapper>
<CardTitle>
<h2>{details.title}</h2>
<h3>{details.title}</h3>
</CardTitle>
</CardTextWrapper>
</CardImage>
</StyledCard>
)
}
export default DestCard;
I want to know how can I route by clicking the card to another page.
The best bet is just to make the card a styled button component and then use useNavigate() to change pages from there.
import * as React from 'react';
import {
StyledCard,
CardImage,
CardTextWrapper,
CardTitle
} from './Card.style.js';
import { useNavigate } from 'react-router-dom';
function DestCard({ details }) {
const navigate = useNavigate();
// console.log(details.image);
return (
<button classname="styledButton" onClick={() => navigate('/route')}>
<CardImage bg= {details.image}>
<CardTextWrapper>
<CardTitle>
<h2>{details.title}</h2>
<h3>{details.title}</h3>
</CardTitle>
</CardTextWrapper>
</CardImage>
</button>
)
}
export default DestCard;
You can add whatever styles are needed to the card to make it obvious to the user that it's clickable.

Warning: Each child in a list should have a unique "key" prop. how to fix this?

Ive been using this project with out a problem and now all of a sudden I keep getting this error and it won't show my notes when I click on the my notes section. What do I have to do for it to go away. The backend is up and running and I can see the static data but it wont show on the app
import { makeStyles } from '#mui/styles'
import React from 'react'
import { Drawer } from '#mui/material'
import { Typography } from '#mui/material'
import List from '#mui/material/List'
import ListItem from '#mui/material/ListItem'
import ListItemIcon from '#mui/material/ListItemIcon'
import ListItemText from '#mui/material/ListItemText'
import { AddCircleOutlineOutlined, SubjectOutlined } from '#mui/icons-material'
import { useHistory, useLocation } from 'react-router-dom'
import AppBar from '#mui/material/AppBar'
import Toolbar from '#mui/material/Toolbar'
import { format } from 'date-fns'
import { red } from '#mui/material/colors'
const drawerWidth = 240 // 500 - subtract this number from
const useStyles = makeStyles((theme) => {
return{
page: {
background: '#E5E4E2',
width: '100%',
padding: theme.spacing(3)
},
drawer: {
width: drawerWidth
},
drawerPaper: {
width: drawerWidth
},
root: {
display: 'flex' //places the drawer side by side with the page content
},
active: {
background: '#E5E4E2'
},
// title:{
// padding: theme.spacing(13),
// alignItems: 'center'
// },
}})
export default function Layout({ children }) {
const classes = useStyles()
const history = useHistory()
const location = useLocation()
const menuItems = [
{
text: 'My Projects',
icon: <SubjectOutlined color="secondary" />,
path: '/'
},
{
text: 'Create Project',
icon: <AddCircleOutlineOutlined color="secondary" />,
path: '/create'
}
]
return (
<div className={classes.root}>
{/* side drawer */}
<Drawer
className={classes.drawer}
variant='permanent' //Lets MUI know we want it on the page permanently
anchor="left" // position of drawer
classes={{ paper: classes.drawerPaper}}
>
<div>
<Typography variant="h5" sx={{textAlign: 'center'}}>
Projects
</Typography>
</div>
{/* List / Links */}
<List>
{menuItems.map(item => (
<div className={location.pathname == item.path ? classes.active : null}>
<ListItem key={item.text} button onClick={() => history.push(item.path)}>
<ListItemIcon>{item.icon}</ListItemIcon>
<ListItemText primary={item.text} />
</ListItem>
</div>
))}
</List>
</Drawer>
<div className={classes.page}>
<div className={classes.toolbar}></div>
{children}
</div>
</div>
)
}
enter image description here
Updated
I'm sorry, of course, you should just move key to the parent div. I didn't notice it. Chris who answered in the comments is right and my answer was not needed. I rewrote the answer.
To have an unique key use index in map or like you did item.text if text is unique for each element in map.
menuItems.map((item,index) =>
The idea is that map has to contain unique key for each element.
In result we have:
<div key={item.text} className={location.pathname == item.path ? classes.active : null}>
or
<div key={index} className={location.pathname == item.path ? classes.active : null}>
And you need to remove key from the List.
Hope this helps! Regards,

when state is changed, ckeditor5 is rendered in duplicate in react

currently, i'm trying to create on/Off function to appear or disappear Ckeditor5
below my code
import { Box, Button, styled, Typography } from "#mui/material";
import React from "react";
import { CKEditor } from "#ckeditor/ckeditor5-react";
import ClassicEditor from "#ckeditor/ckeditor5-build-classic";
const Description = ({ description }) => {
const [isEdit, setIsEdit] = React.useState(false);
const handlerOnOff = () => {
setIsEdit((prev) => !prev);
};
return (
<Root>
<Box>
<Typography component="span">Description</Typography>
<Button onClick={handlerOnOff}>Edit</Button>
</Box>
<Box>
{isEdit ? (
<div>
<CKEditor
config={{
toolbar: [
"heading",
"|",
"bold",
"italic",
"bulletedList",
"numberedList",
"blockQuote"
]
}}
data={description}
editor={ClassicEditor}
/>
</div>
) : (
<>{description}</>
)}
</Box>
</Root>
);
};
const Root = styled("div")(({ theme }) => ({
marginBottom: "60px",
"& .ck-content": {
minHeight: "200px"
}
}));
export default Description;
and codesandbox
https://codesandbox.io/embed/suspicious-mahavira-eoeip1?fontsize=14&hidenavigation=1&theme=dark
when click button named Edit and changed true of state name isEdit, Ckeditor is rendered in duplicate

How to make Gatsby Link receive props as parameter and turn off click cursor

I have a component wrapper to cut some repetitive code on my application.
This wrapper has some props, so I can choose if I want to print a text with an icon or an icon that is a link to another page.
My objective is to render text with an icon and the icon is not clickable as a link, but if I render just an icon the icon is clickable as link.
rowListComponent:
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import PeopleIcon from "#material-ui/icons/People";
import { Link } from "gatsby";
import List from "#material-ui/core/List";
import ListItem from "#material-ui/core/ListItem";
import ListItemIcon from "#material-ui/core/ListItemIcon";
import ListItemText from "#material-ui/core/ListItemText";
import Button from "#material-ui/core/Button";
export default function RowListComponent(props) {
const style = styles();
return (
<List className={style.listSize}>
<ListItem className={style.listSize}>
<Link to={`/${props.component}/${props.link}`}>
<ListItemIcon>{props.icon}</ListItemIcon>
</Link>
<ListItemText>{props.name}</ListItemText>
</ListItem>
</List>
);
}
I want to use this component wrapper on another component and i use it like this:
return (
<div>
<MaterialTable
icons={tableIcons}
title={<h1 className={style.title}>Users</h1>}
columns={[
{
title: "Name",
field: "name",
render: rowData => (
<RowListComponent
icon={<PeopleIcon className={style.iconColor} />}
name={rowData.name}
/>
)
},
{
title: "Details",
field: "details",
render: rowData => (
<RowListComponent
icon={<ListAltIcon className={style.iconColor} />}
component={"users"}
link={rowData.details}
/>
)
}
]}
data={state.users}
options={{
search: true
}}
/>
</div>
);
My problem is that I want to make the link active or not with a prop as well, so when you pass the mouse over the link the cursor does not change.
UPDATED:
I come with a solution but it's not what I want but it works.
export default function RowListComponent(props) {
const style = styles();
return (
<List className={style.listSize}>
<ListItem className={style.listSize}>
<Link
to={`/${props.component}/${props.link}`}
className={props.isActive}
>
<ListItemIcon>{props.icon}</ListItemIcon>
</Link>
<ListItemText>{props.name}</ListItemText>
</ListItem>
</List>
);
}
I set the isActive prop: isActive = {style.disabledLink} and this style is pointerEvents: "none" but what i really wanted was just to say isActive = {true or false}
I think you want something like this:
<Link to={`/${props.component}/${props.link}`} className={`${props.isActive ? "is-active" : "not-active"}`}>
Now you can add css to the 'is-active' class that sets 'pointerEvents' to none. And you can pass a bool value to 'isActive'.
I have also seen this nice package to join conditional classnames. Then this would be the solution:
<Link to={`/${props.component}/${props.link}`} className={classNames({ 'is-active': props.isActive })}>
Or if you want to directly add the style without a classname:
<Link to={`/${props.component}/${props.link}`} style={{ pointerEvents: props.isActive ? 'none': 'auto'}}>

How can i use component methods in other components

I created a notification component. I want to use it in other components
How can i use the this.addNotification() in my navbar.js? I tried many ways but none was working, so maybe someone here knows the best way to do this. I will be glad for any help!
//Notifications.js
import React from "react";
import ReactNotification from "react-notifications-component";
import "react-notifications-component/dist/theme.css";
export default class Notifications extends React.Component {
constructor(props) {
super(props);
this.addNotification = this.addNotification.bind(this);
this.notificationDOMRef = React.createRef();
}
addNotification() {
this.notificationDOMRef.current.addNotification({
title: "Awesomeness",
message: "Awesome Notifications!",
type: "success",
insert: "top",
container: "top-right",
animationIn: ["animated", "fadeIn"],
animationOut: ["animated", "fadeOut"],
dismiss: { duration: 2000 },
dismissable: { click: true }
});
}
render() {
return (
<div className="app-content">
<ReactNotification ref={this.notificationDOMRef} />
<button ref={this.addNotification} className="btn btn-primary">
Add Awesome Notification
</button>
</div>
);
}
}
//Navbar.js
// I want to use the notifications here, but i don't know how
// this.addNotification() - > this is working in the notifications file, `but not here`
import React from 'react';
import {
Collapse,
Navbar,
NavbarToggler,
NavbarBrand,
Nav,
NavItem,
NavLink,
UncontrolledDropdown,
Dropdown,
DropdownToggle,
DropdownMenu,
DropdownItem, Container, Row, Col } from 'reactstrap';
import LoginModal from './LoginModal';
import User from './User';
// i just import the class
import Notifications from './Notifications';
export default class MyNavbar extends User {
constructor(props) {
super(props);
this.toggle = this.toggle.bind(this);
this.toggleDropDown = this.toggleDropDown.bind(this);
this.state = {
isOpen: false,
userName: this.getUserLogin(),
userEmail: this.getUserEmail(),
firstTime: this.getFirstTime(),
dropdownOpen: false,
info:""
};
}
showError(){
this.addNotification()
// I want something like this, but i don't know how to do this
}
toggle() {
this.setState({
isOpen: !this.state.isOpen
});
}
toggleDropDown() {
this.setState({
dropdownOpen: !this.state.dropdownOpen
});
}
render(props) {
return (
<div>
<Container>
<Navbar color="da" light expand="md">
<NavbarBrand href="/">Pies Fajny Jest</NavbarBrand>
<NavbarToggler onClick={this.toggle} />
<Collapse isOpen={this.state.isOpen} navbar>
{this.state.userName ?
<Nav className="ml-auto" navbar>
<Dropdown isOpen={this.state.dropdownOpen} toggle={this.toggleDropDown}>
<DropdownToggle className="btn btn-danger" caret>
{this.state.userName}
</DropdownToggle>
<DropdownMenu>
<DropdownItem header>Header</DropdownItem>
<DropdownItem>Some Action</DropdownItem>
<DropdownItem disabled>Action (disabled)</DropdownItem>
<DropdownItem divider />
<DropdownItem>Foo Action</DropdownItem>
<DropdownItem>Bar Action</DropdownItem>
<DropdownItem onClick={ () => this.logout(this) }>Wyloguj</DropdownItem>
</DropdownMenu>
</Dropdown>
</Nav>
:
<Nav className="ml-auto" navbar>
<NavItem className="LoginRegister" >
<LoginModal
buttonLabel="Zaloguj się"
title="Logowanie"
inputSubmit="Zaloguj się"
/>
</NavItem>
<NavItem className="LoginRegister" >
<LoginModal
buttonLabel="Zarejestruj się"
title="Rejestracja"
inputSubmit="Zarejestruj się"
register="register"
/>
</NavItem>
</Nav>}
</Collapse>
</Navbar>
</Container>
</div>
);
}
}
you can pass the method as props eg
<Notifications addNotification={this.addNotification} />
an when you console this.props.addNotification you get that function there in Notifications.js
I tried to execute the method showError() and i got this:
Uncaught TypeError: Cannot read property 'current' of null
this line: notificationDOMRef.current.addNotification({
Try to use this, but I think the best way to create notifications is to use listeners. But I think this will work.
Also avoid to use ".bind()" on constructor, instead use arrow functions.
//Notifications.js
import React from "react";
import ReactNotification from "react-notifications-component";
import "react-notifications-component/dist/theme.css";
// Create a variable
let notificationDOMRef = null
// export this function and import where you want to use
export const addNotification = () => {
notificationDOMRef.current.addNotification({
title: "Awesomeness",
message: "Awesome Notifications!",
type: "success",
insert: "top",
container: "top-right",
animationIn: ["animated", "fadeIn"],
animationOut: ["animated", "fadeOut"],
dismiss: { duration: 2000 },
dismissable: { click: true }
});
}
export default class Notifications extends React.Component {
render() {
return (
<ReactNotification ref={ref => notificationDOMRef = ref} />
);
}
}
//Navbar.js
// I want to use the notifications here, but i don't know how
// this.addNotification() - > this is working in the notifications file, `but not here`
import React from 'react';
import {
Collapse,
Navbar,
NavbarToggler,
NavbarBrand,
Nav,
NavItem,
NavLink,
UncontrolledDropdown,
Dropdown,
DropdownToggle,
DropdownMenu,
DropdownItem, Container, Row, Col } from 'reactstrap';
import LoginModal from './LoginModal';
import User from './User';
// just import the class and the function
import Notifications, { addNotification } from './Notifications';
export default class MyNavbar extends User {
constructor(props) {
super(props);
this.toggle = this.toggle.bind(this);
this.toggleDropDown = this.toggleDropDown.bind(this);
this.state = {
isOpen: false,
userName: this.getUserLogin(),
userEmail: this.getUserEmail(),
firstTime: this.getFirstTime(),
dropdownOpen: false,
info:""
};
}
showError(){
// you can use here
addNotification()
}
toggle() {
this.setState({
isOpen: !this.state.isOpen
});
}
toggleDropDown() {
this.setState({
dropdownOpen: !this.state.dropdownOpen
});
}
render(props) {
return (
<div>
// You need to render your component
<Notifications />
<Container>
<Navbar color="da" light expand="md">
<NavbarBrand href="/">Pies Fajny Jest</NavbarBrand>
<NavbarToggler onClick={this.toggle} />
<Collapse isOpen={this.state.isOpen} navbar>
{this.state.userName ?
<Nav className="ml-auto" navbar>
<Dropdown isOpen={this.state.dropdownOpen} toggle={this.toggleDropDown}>
<DropdownToggle className="btn btn-danger" caret>
{this.state.userName}
</DropdownToggle>
<DropdownMenu>
<DropdownItem header>Header</DropdownItem>
<DropdownItem>Some Action</DropdownItem>
<DropdownItem disabled>Action (disabled)</DropdownItem>
<DropdownItem divider />
<DropdownItem>Foo Action</DropdownItem>
<DropdownItem>Bar Action</DropdownItem>
<DropdownItem onClick={ () => this.logout(this) }>Wyloguj</DropdownItem>
</DropdownMenu>
</Dropdown>
</Nav>
:
<Nav className="ml-auto" navbar>
<NavItem className="LoginRegister" >
<LoginModal
buttonLabel="Zaloguj się"
title="Logowanie"
inputSubmit="Zaloguj się"
/>
</NavItem>
<NavItem className="LoginRegister" >
<LoginModal
buttonLabel="Zarejestruj się"
title="Rejestracja"
inputSubmit="Zarejestruj się"
register="register"
/>
</NavItem>
</Nav>}
</Collapse>
</Navbar>
</Container>
</div>
);
}

Categories

Resources