const SortableItem = SortableElement(({ i, value}) =>
<ListItem button onClick={this.handleClick(i, value.title)}>
<ListItemText primary={<div className={classes.title}>{value.title}</div>}/>
</ListItem>
);
when I call this SortableItem in SortableContainer and then in render use it, when clicking on one item it call the handleClick function for all elements the same time. What to do?
Call click event like this.
<ListItem button onClick={()=> this.handleClick(i, value.title)}>
Related
I have a drawer component where I put my List items in a List, on each List item click I'm navigating to respective page. I'm able to do this successfully but when I want to update state on each list item click, it is not updating on single click. I want to update my state with respective index. If I remove component & to props in ListItem, updating state is working fine. Can someone please help me in this.
const [value, setValue] = useState(0);
const handleListItemClick = (event, index) => {
setValue(index);
}
<ListItem
button
selected={selected}
onClick={event => handleListItemClick(event, 0)}
component={Link}
to={"/home"}
>
<ListItem
button
selected={selected}
onClick={event => handleListItemClick(event, 1)}
component={Link}
to={"/some-page"}
>
I'm working on a project in which I need a sidebar with nested lists created with material UI, if I go to demo and copy the nested list code it's all fine but it comes with alot of code duplication. So after some digging I found recursive rendering function gist which is written with classes. I'm using react hooks and the function logic is not working as expected.
Problem:
I have 3 level navigation, A parent, then child and child contains more items (grandchildren to parent). So when I click on the parent everything is fine children items appears, but when I click any of the children element the whole list closes.
here is my Code:
// useState hook with empty object as an initial Value
const [open1, setOpen1] = React.useState({});
// this method sets the current state of a menu item i.e whether it is in expanded or collapsed or a collapsed state
const handleClick = (param) => {
setOpen1(prevState => ({[param]: !prevState[param]}));
};
// if the menu item doesn't have any child, this method simply returns a clickable menu item that redirects to any location and if there is no child this method uses recursion to go until the last level of children and then returns the item by the first condition.
function nestedMenu(items) {
return items.map((nav) => {
if (!nav.children) {
return (
<div key={nav.id}>
<ListItem button>
<ListItemText primary={nav.name} />
</ListItem>
</div>
)
}
return (
<div key={nav.id}>
<ListItem button onClick={()=>handleClick(nav.name)}>
<ListItemText primary={nav.name} />
{open1[nav.name] ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse in={open1[nav.name] } timeout="auto" unmountOnExit>
<List component="div" disablePadding>
{ nestedMenu(nav.children)}
</List>
</Collapse>
</div>
)
})
}
After that I'm calling the nestedMenu function with json data as parameter in my return method
<List>
{nestedMenu(Links.items)}
</List>
Can anyone please explain what I'm doing wrong in all this, I have been working my head out to locate the problem. Any help would be much appreciated.
the problem is you change the whole open1 object :
const handleClick = (param) => {
setOpen1(prevState => ({[param]: !prevState[param]}));
};
for example if u have {p1:true, p2:false} and execute handkeClick('p1'),
open1 will be {p1:false}.
you need to keep the other members of open1 unchange and just update the one you want :
const handleClick = (param) => {
setOpen1(prevState =>
retrun {...prevState ,[param]: !prevState[param]}
);
};
I have an App component that renders a MenuBar component. In that MenuBar, I render ListItems (from material-ui) and pass the following as a prop:
onClick = (e) => {
const id = e.target.id;
console.log(id);
console.log('called');
}
the MenuBar component:
render() {
const onClick = this.props.onClick;
const titles = ["Home", "About", "Docket", "Polls", "News"];
const listItems = titles.map(title =>
<ListItem button id={title} onClick={onClick} key={title}>
<ListItemText primary={title} />
</ListItem>);
return (
<List
component="ul"
className="menu-bar">
{listItems}
</List>
);
}
I want to use this title, which I try to retrieve from the event, so that I can render a Home component, or About component, etc, depending on which ListItem is selected. But when I run this and click randomly on some of the ListItems in my browser, the title is only logged to the console sometimes (seemingly randomly). What is the best way for me to access which ListItem was selected, or why is the console logging the title only sometimes?
Here is what I get in the browser console:
Docket
called
called
Polls
called
News
called
The reason why you don't consistently get id is that the html element triggering the click event is not always what you think. Please see this sandbox for an example. When you click on any of the ListItem, sometimes you get (if you click to the left of where the letter is, based on my trials):
<div class="MuiButtonBase-root-1883 MuiListItem-root-1871 MuiListItem-default-1874 MuiListItem-gutters-1879 MuiListItem-button-1880" tabindex="0" role="button" id="a">...</div>
where the id is present. But other times you get:
<span class="MuiTypography-root-1892 MuiTypography-subheading-1899 MuiListItemText-primary-1889">a</span>
where the id is missing.
A solution to this is to pass title directly to the onClick function:
<ListItem button id={title} onClick={() => onClick(title)}>
...
</ListItem>
Accordingly, the onClick function should be updated as follows:
onClick = (title) => {
console.log(title);
console.log('called');
}
currentTarget is what worked it for me. (instead of just target)
I've read elsewhere that maybe MUI is resulting in unexpected behavior. Similar to what Claire Lin stated, in the Material UI List (and for me, it was nested in a MUI Drawer as well), when clicking on a button, the actual target was different from what I expected. The solution I found is to use the following:
Try e.currentTarget.getAttribute('value') , where "value" is data placed on the ListItem.
Here's how I added it. See "value" being assigned, and then logged below in the onClick. (...I tried to remove most of the extra code, but there is still a bit of superfluous code in there just bc it provides context.)
return (
//removed extra code for brevity
<Drawer
anchor={'left'}
open={drawerOpen}
onClose={toggleDrawerOpen(false)}
>
<List>
{itemsList.map((item, index) => {
const { text, icon, id } = item
return (
<ListItem
button
key={id}
value={index} // <<<< HERE!!!
onClick={(e) => {
console.log(e.currentTarget.getAttribute('value')) // <<<< HERE!!!
setDrawerOpen(false)
}}
>
{icon && <ListItemIcon>{icon}</ListItemIcon>}
<ListItemText primary={text} />
</ListItem>
)
})}
</List>
</Drawer>
...Again, I used "value" and assigned it the "index".
currentTarget is the trick.
I need to make the sidebar list clickable so when you click on a location on the sidebar, its corresponding marker will open the infowindow. Below is the code I used:
Click List function:
clickListItem = venues => {
const marker = this.state.markers.find(marker.id === venues.id);
this.handleMarkerClick(marker);
console.log(venues.name);
};
Then I tried to call it on the sidebar:
<List>
{this.props.venues &&
this.props.venues.map(({ venue }, index) => (
<ListItem
button
key={index}
onClick={() => this.props.clickListItem(this.props)}
>
<ListItemText primary={venue.name} />
</ListItem>
))}
</List>
When I click on a location, nothing happens. How do I get the list to call the marker function that opens the infowindow? Full code here.
Sidebar.js, line 154. For a start, try changing that to:
onClick={() => this.props.clickListItem(venue)}
I have a material ui list in my one of the component. When I click any item of this list, I go to another listView. I am using router to go to another listView. And using onClick method. Whenever I click any list item of first list I print "firstList clicked". and whenever I click any item if second list, it print "secondList clicked".
Here is my Problem:
When I click the ListItem of first list, the console.log("secondList clicked") also gets printed with "firstList Clicked" automatically. I have four list items in second list, so my console print output looks like this
firstList Clicked
secondList Clicked
secondList Clicked
secondList Clicked
secondList Clicked
Why is this happening?
Here is my code.
SecondList code
class TagListItemDetails extends Component {
handleClick() {
console.log("secondList clicked")
}
handleButtonClick() {
browserHistory.push("TagList")
}
render() {
return (
<MuiThemeProvider>
<div>
<List id="parent-list-tags">
<ListItem primaryText="Kitchen" onTouchTap={this.handleClick()}/>
<ListItem primaryText="Beach" onClick={this.handleClick()}/>
<ListItem primaryText="Marriage" onClick={this.handleClick()}/>
<ListItem primaryText="Garden" onClick={this.handleClick()}/>
</List>
<div className="backButton">
<RaisedButton backgroundColor="#293C8E" label="Back" onClick={this.handleButtonClick} labelColor="white">
</RaisedButton>
</div>
</div>
</MuiThemeProvider>
);
}
}
const mapStateToProps =(state) =>{
return {
tags: state.tagReducer
};
};
function matchDispatchToProps(dispatch){
return bindActionCreators({tagSelected: tagSelected}, dispatch);
}
export default connect(mapStateToProps, matchDispatchToProps)(TagListItemDetails);
firstList
export default class TagList extends Component {
handleClicked() {
console.log("firstList Clicked")
browserHistory.push("TagListItemDetails")
}
render() {
return (
<div>
<List id="parent-list-tags" >
<ListItem primaryText="Scene" onClick={this.handleClicked} />
<Divider/>
<ListItem primaryText="Actors" onClick={this.handleClicked} />
<Divider/>
<ListItem primaryText="Emotions" onClick={this.handleClicked} />
<Divider/>
<ListItem primaryText="Actions" onClick={this.handleClicked}/>
<Divider/>
<ListItem primaryText="Objects" onClick={this.handleClicked}/>
<Divider/>
<ListItem primaryText="Compliance" onClick={this.handleClicked} />
</List>
<AddButton />
</div>
)
}
};
The problem is that in the SecondList, you are invoking the handleClick method as soon as the component is loaded. Try removing the parentheses () from the onClick handler. So instead of
<ListItem primaryText="Beach" onClick={this.handleClick()}/>
you can use:
<ListItem primaryText="Beach" onClick={this.handleClick}/>
------------------------------------------------------^^ No parentheses here
One way of passing arguments to a click handler passed as a prop is to use the fat arrow function:
onClick={() => this.props.itemSelected(2)}
// or if you want to pass the event as well:
onClick={(event) => this.props.itemSelected(2, event)}
Also, here is a demo of how to fire two functions on onClick event : http://codepen.io/PiotrBerebecki/pen/YGRQrG