1

I have some data in arrays. I am getting it by using map, as you see in the below example. Also, i pass that into the button. Now, if, i select a button, it will get selected. But, if i select the next button, the previous button will get unselected and the current button will get selected. I don't want it to happen. I want to select multi buttons, if it all get clicked.

Thanks in advance.

Below is the Solution

   import React, { Component } from 'react';


const BUTTONS = [
    {id:0, title:'button1'},
    {id:1, title:'button2'},
    {id:2, title:'button3'}
]
class Map extends Component {
    constructor(props){
        super(props);
        this.state = {
            values: []
        }
    }
    handleButton = button => {
        let tmp = this.state.values;
        if (this.state.values.includes(button)) {
            this.setState({
                values: this.state.values.filter(el => el !== button)
            })
        } else {
            tmp.push(button);
            this.setState({
                values: tmp
            })
        }
    }

    render () {
        return (
            <div>
                {BUTTONS.map(bt=>(
                <button 
                    key={bt.id} 
                    onClick={()=>this.handleButton(bt.id)} 
                    className={this.state.values.includes(bt.id) ? "buttonPressed" : "button"}>
                    {bt.title}
                </button>
                ))}
            </div>
        );
    }
} 

export default Map;
1
  • I may do something like: this.state = { clickedButtons: {}} Then on the buttons className={this.state.clickedButtons[bt.id] ? "buttonPressed" : "button"}> Then the handleButton would look something like: this.setState({clickedButtons:{ [button]: true }}); Commented Apr 1, 2019 at 11:14

3 Answers 3

1
  1. Selecting multiple buttons

    you'd better use the state as an array.

this.state = {
  values: []
}

and you can push items.

let tmp = this.state.values;
tmp.push(button);
this.setState({
  values: tmp
});

in render() you have to check state.values has bt.id

className={this.state.values.includes(bt.id) ? "buttonPressed" : "button"
  1. Toggling multiple buttons

    you can check in handleButton() whether that selected button is already selected

handleButton = button => {
  if (this.state.values.includes(button)) {
    this.setState({
      values: this.state.values.filter(el => el !== button)
    })
  }

const BUTTONS = [
    { id: 0, title: 'button1' },
    { id: 1, title: 'button2' },
    { id: 2, title: 'button3' }
]
class Map extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            values: []
        }
    }

    handleButton = button => {
        let tmp = this.state.values;
        if (this.state.values.includes(button)) {
            this.setState({
                values: this.state.values.filter(el => el !== button)
            })
        } else {
            tmp.push(button);
            this.setState({
                values: tmp
            })
        }
    }

    render() {
        return (
            <div>
                {BUTTONS.map(bt => (
                    <button
                        key={bt.id}
                        onClick={() => this.handleButton(bt.id)}
                        className={this.state.values.includes(bt.id) ? "buttonPressed" : "button"}>
                        {bt.title}
                    </button>
                ))}
            </div>
        );
    }
}

export default Map;

Sign up to request clarification or add additional context in comments.

5 Comments

Now, i am getting an error "TypeError: Cannot read property 'includes' of undefined"
@JeyanthKanagaraj do you use let tmp?
Yeah, now that error got cleared. But, when i click the button, it's doing noting. Not, even changing the class name. I updated the code above
@JeyanthKanagaraj className={this.state.values.includes(bt.id) ? "buttonPressed" : "button"}>
Oh, my bad. Thank You @zynkn
1

The reason your button is getting deselected is because you're overwriting this.state.value every time you click a button.

If you want multiple selections, you'll need to hold all of the selected items in the state, as an array, and then when rendering, check if the button id is included in that array.

Something like:

import React, { Component } from 'react';


const BUTTONS = [
    {id:0, title:'button1'},
    {id:1, title:'button2'},
    {id:2, title:'button3'}
]
class Map extends Component {
    constructor(props){
        super(props);
        this.state = {
            selectedValues: []
        }
    }

    handleButton = buttonId => {
        let newSelectedValues = this.state.selectedValues;
        newSelectedValues.push(buttonId);
        this.setState({
            selectedValues: newSelectedValues
        })
    }

    render () {
        return (
            <div>
                {BUTTONS.map(bt => (
                    <button 
                        key={bt.id} 
                        onClick={()=>this.handleButton(bt.id)} 
                        className={this.state.selectedValues.includes(bt.id) ? "buttonPressed" : "button"}>
                            {bt.title}
                    </button>
                ))}
            </div>
        );
    }
} 

export default Map;

2 Comments

Now, i am getting an error "TypeError: Cannot read property 'includes' of undefined"
The answer has gone through a couple of edits and would have resulted in that. It should be fixed now.
0

if you need multiple selections you need an array:

this.state = {
   values:[]
}

and push it on each clicks Correct way to push into state array

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.