How to pass parameters in onClick event bind? - reactjs

I've set up an onClick event in a ListItem. Then called .bind on the method invoked to pass in the clicked list item's id and name values.
The following SO question suggested using bind but it seems adding the onCLick event to the ListItem breaks the list binding.
Before adding the click event the list span binding to the asset.name is working as expected and the list is populated.
Also if I try onClick={this._onAssetSelected() with no parameters the click event doesn't work.
Question:
How can you pass parameters in an onClick event bind in JSX?
List definition:
<List selectable={true} selected={0}>
{
this.state.data.map(function (asset) {
return (
<ListItem justify="between" onClick={this._onAssetSelected.bind(this, asset.name, asset.id)} >
<span>{asset.name}</span>
</ListItem>
);
})
}
</List>
Method called from the click event:
_onAssetSelected(assetName, assetID) {
console.log(assetName);
console.log(assetID);
}

You can do this. Define an anonymous function as the callback, inside which you call your method with the parameters. Hop ut helps!
<List
selectable={true}
selected={0}>
{
this.state.data.map(function (asset) {
return (
<ListItem
justify="between"
onClick={(e) => this._onAssetSelected(asset.name, asset.id, e)} >
<span>{asset.name}</span>
</ListItem>
);
})
}
</List>

Related

How do I add an 'onClick' event to a mapped data?

{data && data.map((data) => <Cards data={data} key={data._id} />)}
The code checks if there is data and of course if there is, it displays the card component.
I want to add a click event so I could know which of the list of cards retuned in particular is being clicked.
I've done this, it does not work.
{data && data.map((data) => <Cards onClick={click} data={data} key={data._id} />)}
and here is the click function
const click = (e) => {
e.preventDefault();
console.log("clicked");
};
You have a typo onClick and not onCLick
Edit:
You can wrap the <Card/> inside a <div> and add onClick to the div or inside the <Card/> component add onClick to the parent component and pass your click function as a prop

function called for every row in the datagrid although I want to call it only onClick in react

I got this function:
const DataEdit = ({id}) => {
console.log(id)
}
and this column inside my DataGrid(imported from #miu/x-data-grid):
{
field:'Delete',
headerName:'Delete',
width:100,
sortable:false,
disableClickEventBubbling:true,
renderCell: (params) => {
return(
<div>
<IconButton
aria-label="add an alarm"
onClick ={DataEdit(params)}
>
<Delete
color="error"
style={{cursor:'pointer'}}
/>
</IconButton>
</div>
)
}
},
for some reason the DataEdit function sends console log for every row in the DataGrid in the page, first of all, why is that? second of all, how can I make it work only when I click the IconButton.
Thanks in advance.
As you created it, it is a normal function so it will be loaded in stack and executed as component renders (it will return value to onClick). On the other hand if you rewrite it as:
onClick ={() => DataEdit(params)}
it will create a function DataEdit and assign it to onClick, thus will be executed only when clicked.

Material UI Nested lists using recursive render is not working with react hooks

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]}
);
};

Getting id from an event handler that was passed to a button component in React?

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.

Material UI List onClick fires click event on nested list

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

Resources