Reputation: 423
I want to create a country list that the ListItems in it are clickable and each ListItem has an icon near to text when clicked. I created a list and I implemented the clickable property of lists. But, when I click one list item in the list, I cannot select the other item in 1 click, it first deselects the previous one and then selects the other. This is the part of the code that my implementation is included:
class CountryList extends Component {
constructor(props) {
super(props);
this.state = {clicked: false};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(state => ({
clicked: !state.clicked
}));
}
render() {
const {classes} = this.props;
const { clicked } = this.state;
let listItems = myList.map((item) =>
<>
<ListItem className={ clicked ? classes.listItemClicked : classes.listItemNotClicked }
onClick={this.handleClick} classes={classes.ListItem} button key={item.id}>
{clicked ?
<ListItemIcon><DoneIcon style={{ color: 'rgb(239, 239, 239)', fontSize: '2.2rem' }}/></ListItemIcon>
: <ListItemIcon><DoneIcon style={{ display: 'none', color: 'rgb(239, 239, 239)', fontSize: '2.2rem', backgroundColor: 'rgb(239, 239, 239)' }}/></ListItemIcon>}
<ListItemText classes={{primary: classes.listItemText}} primary={item.value} />
</ListItem>
<Divider />
</>
);
return (
<List className={classes.list}>{listItems}</List>
);
}
}
const myList = [
{id: 1, value: 'Albania'}, {id: 2, value: 'Austria'}, {id: 3, value: 'Belarus'}, {id: 4, value: 'Belgium'},
{id: 5, value: 'Bosnia'}, {id: 6, value: 'Bulgaria'}, {id: 7, value: 'Croatia'}, {id: 8, value: 'Cyprus'},
{id: 9, value: 'Czech'}, {id: 10, value: 'Denmark'}, {id: 11, value: 'Estonia'}, {id: 12, value: 'Finland'},
{id: 13, value: 'France'}, {id: 14, value: 'Germany'}, {id: 15, value: 'Greece'}, {id: 16, value: 'Hungary'},
{id: 17, value: 'Iceland'}, {id: 18, value: 'Ireland'}, {id: 19, value: 'Italy'}, {id: 20, value: 'Latvia'},
{id: 21, value: 'Lithuania'}, {id: 22, value: 'Luxembourg'}, {id: 23, value: 'Macedonia'},
{id: 24, value: 'Malta'}, {id: 25, value: 'Moldova'}, {id: 26, value: 'Montenegro'},
{id: 27, value: 'Netherlands'}, {id: 28, value: 'Norway'}, {id: 29, value: 'Pakistan'},
{id: 30, value: 'Poland'}, {id: 31, value: 'Portugal'}, {id: 32, value: 'Romania'}, {id: 33, value: 'Russia'},
{id: 34, value: 'Serbia'}, {id: 35, value: 'Slovakia'}, {id: 36, value: 'Slovenia'},
{id: 37, value: 'Spain'}, {id: 38, value: 'Sweden'}, {id: 39, value: 'Switzerland'}, {id: 40, value: 'Turkey'},
{id: 41, value: 'Ukraine'}, {id: 42, value: 'Others'}
];
This is the code in App.js file:
<CountryList myList={myList} />
Also, I added an icon before the text. When I click 1 item, it shows the icon but, it also shows another element icon if my mouse is on it. I want to show the icon of the clicked element. How can I achieve this?
This is the screenshot:
If you look at carefully, there is an icon next to Belgium.
This is the link for the code in codesandbox: https://codesandbox.io/s/gifted-snow-5p1gd?file=/src/Country.js
Upvotes: 3
Views: 13113
Reputation: 21901
Here is a working demo
You need to keep a active list item in a state, as i see in your code its this.state.clicked
which is a boolean, so now you don't have a way to set the styles of clicked element because there is no reference to which is selected
set a state to keep the clicked item
this.state = { clickedItem: "" };
change onClick to.
<ListItem
key={item.id}
className={
this.state.clickedItem === item.id
? classes.listItemClicked
: classes.listItemNotClicked
}
onClick={() => this.handleClick(item)}
>
in onCLick set the clicked items to the state
handleClick(item) {
this.setState({
clickedItem: item.id
});
}
Now you have the clicked item in the state, in the next render (which will be happen due to above state change) you can have the below logic in the render
<ListItem
key={item.id}
className={
this.state.clickedItem === item.id //if item.id === clickedItemId then add a separate css class
? classes.listItemClicked
: classes.listItemNotClicked
}
onClick={() => this.handleClick(item)}
>
<ListItemIcon>
//if item.id === clickedItemId then show the DoneIcon
{this.state.clickedItem === item.id && (
<DoneIcon
style={{ color: "rgb(239, 239, 239)", fontSize: "2.2rem" }}
/>
)}
</ListItemIcon>
<ListItemText primary={item.value} />
</ListItem>
Upvotes: 7
Reputation: 11
You have to map clicked with index. Try this:
class CountryList extends Component {
constructor(props) {
super(props);
this.state = {clicked: null};
this.handleClick = this.handleClick.bind(this);
}
handleClick(key) {
this.setState(state => ({
clicked: key
}));
}
render() {
const {classes} = this.props;
const { clicked } = this.state;
let listItems = myList.map((item, index) =>
<>
<ListItem className={ clicked == index ? classes.listItemClicked : classes.listItemNotClicked }
onClick={this.handleClick} classes={classes.ListItem} button key={item.id}>
{clicked == index ?
<ListItemIcon><DoneIcon style={{ color: 'rgb(239, 239, 239)', fontSize: '2.2rem' }}/></ListItemIcon>
: <ListItemIcon><DoneIcon style={{ display: 'none', color: 'rgb(239, 239, 239)', fontSize: '2.2rem', backgroundColor: 'rgb(239, 239, 239)' }}/></ListItemIcon>}
<ListItemText classes={{primary: classes.listItemText}} primary={item.value} />
</ListItem>
<Divider />
</>
);
return (
<List className={classes.list}>{listItems}</List>
);
}
}
const myList = [
{id: 1, value: 'Albania'}, {id: 2, value: 'Austria'}, {id: 3, value: 'Belarus'}, {id: 4, value: 'Belgium'},
{id: 5, value: 'Bosnia'}, {id: 6, value: 'Bulgaria'}, {id: 7, value: 'Croatia'}, {id: 8, value: 'Cyprus'},
{id: 9, value: 'Czech'}, {id: 10, value: 'Denmark'}, {id: 11, value: 'Estonia'}, {id: 12, value: 'Finland'},
{id: 13, value: 'France'}, {id: 14, value: 'Germany'}, {id: 15, value: 'Greece'}, {id: 16, value: 'Hungary'},
{id: 17, value: 'Iceland'}, {id: 18, value: 'Ireland'}, {id: 19, value: 'Italy'}, {id: 20, value: 'Latvia'},
{id: 21, value: 'Lithuania'}, {id: 22, value: 'Luxembourg'}, {id: 23, value: 'Macedonia'},
{id: 24, value: 'Malta'}, {id: 25, value: 'Moldova'}, {id: 26, value: 'Montenegro'},
{id: 27, value: 'Netherlands'}, {id: 28, value: 'Norway'}, {id: 29, value: 'Pakistan'},
{id: 30, value: 'Poland'}, {id: 31, value: 'Portugal'}, {id: 32, value: 'Romania'}, {id: 33, value: 'Russia'},
{id: 34, value: 'Serbia'}, {id: 35, value: 'Slovakia'}, {id: 36, value: 'Slovenia'},
{id: 37, value: 'Spain'}, {id: 38, value: 'Sweden'}, {id: 39, value: 'Switzerland'}, {id: 40, value: 'Turkey'},
{id: 41, value: 'Ukraine'}, {id: 42, value: 'Others'}
];
Upvotes: 0