0

I have a button. I want the button to be clickable once the user has answered all quiz questions. When the button is clicked, I want to call computePiePercentages which calculates the size of pie slices in the pie chart (as well as figuring out if something doesn't fit into the pie chart). I'd like to display this pie chart computePiePercentages is called.

But I'm having trouble with the syntax inside onClick. Before requiring two actions, I was able to use this syntax:

<button onClick={this.computePiePercentages}>Click me</button>

But when I try: <button onClick={function(event){ this.computePiePercentages; this._showResults.bind(null, true)}}>Click </button

I get: Cannot read property 'computePiePercentages' of undefined

class Budget extends React.Component {

  state = {
      data,
      pieChartData: [],
      beyondBudget: {},
      showMessage: bool
  };

  constructor(props) {
    super(props);
    this.state = {
      data,
      pieChartData: [],
      beyondBudget: {},
      showMessage: bool
    };

    // This binding is necessary to make `this` work in the callback
    this.computePiePercentages = this.computePiePercentages.bind(this);

  }

  computePiePercentages(){
    var total = 0
    console.log("hi i am called!!!")
    console.log(this.state.data.selectedQuestions)
    return Object.entries(this.state.data.selectedQuestions).map((element, j)  => {
      console.log(element)
    //return selectedQuestions.map((val, j) => {
      const value = Object.values(element[1])[0]
      total += value

      if(total <= 1600){
        let pieSlice =
             {
               x: name,
               y: value
             };

             this.setState({
                 pieChartData: [...this.state.pieChartData, {x: name, y: value}]
             })
      }
      else {
            const beyondBudget = Object.assign({}, this.state.beyondBudget);

            if (Object.keys(beyondBudget).length == 0) {
                beyondBudget[name] = {};
                beyondBudget[name] = newBudget * -1;
            }
            if (!beyondBudget[name]) {
                beyondBudget[name] = {};
            }
            if (Object.keys(beyondBudget).length > 1) {
                beyondBudget[name] = value;
            }

            this.setState({
                data: {
                    ...this.state.data,
                    selectedQuestions,
                },
                remainingBudget: newBudget,
                beyondBudget: beyondBudget,
            });
        }
    });

}


  handleInputChange = event => {

    let { value, id, name } = event.target;
    value = parseInt(value, 10);

    const selectedQuestions = Object.assign(
      {},
      this.state.data.selectedQuestions
    );



    if (!selectedQuestions[name]) {
      selectedQuestions[name] = {};
    }

    selectedQuestions[name][id] = value;
    console.log(selectedQuestions[name][id])
    this.setState({
                data: {
                    ...this.state.data,
                    selectedQuestions,
                }
    });


  };
  _showResults = (bool) => {
      this.setState({
        showMessage: bool
      });
}
  render() {
      const {
          data,
          remainingBudget,
          pieChartData,
          beyondBudget,
          answeredQuestions,
      } = this.state;
      const questions = data.questions;
      return (
          <div>
              {questions.map((q, i) => (
                  <UL key={i}>
                      <li>
                          <h4>{q.text}</h4>
                      </li>
                      <li>
                          <Options
                              state={this.state}
                              q={q}
                              i={i}
                              handler={this.handleInputChange}
                          />
                      </li>
                  </UL>
              ))}
                <button  onClick={this.computePiePercentages; this._showResults.bind(null, true)}>Click me</button>
                {this.state.showResults &&
                  (<div>
                        <VictoryPie
                            colorScale="blue"
                            data={pieChartData}
                            labels={d => `${d.x}: ${d.y}%`}
                            style={{ parent: { maxWidth: '50%' } }}
                        />

                        {Object.keys(beyondBudget).length > 0 && (
                            <div>
                                <Table>
                                    <tbody>
                                        <tr>
                                            <th>Out of Budget</th>
                                        </tr>
                                        <BrokeBudget
                                            beyondBudget={beyondBudget}
                                        />
                                    </tbody>
                                </Table>
                            </div>
                        )}
                    </div>)
                }
          </div>

      );
  }
  }
maddie
  • 1,854
  • 4
  • 30
  • 66
  • Possible duplicate of [Two parameters inside onClick](https://stackoverflow.com/questions/57467567/two-parameters-inside-onclick) – cccn Aug 27 '19 at 17:27
  • This is a `this` problem that's very common. Best practice, as explained in the React docs, is to bind the methods in the constructor: `this.computePiePercentages = this.computePiePercentages.bind(this);`, and the same for the other method. You can instead use an arrow function as suggested by @ClueMediator, but that comes with a small performance penalty. – Robin Zigmond Aug 27 '19 at 17:29
  • @RobinZigmond oh yup I binded `computePie` in the constructor - tho i forgot to add for the other method. Using the arrow method, only the first method gets called though - I can't get my console.log to print in `_showResults` – maddie Aug 27 '19 at 17:32

2 Answers2

0

You can try it like this.

<button onClick={(event) => { 
    this.computePiePercentages(); 
    this._showResults.bind(null, true);
}}>Click</button>


Here I used arrow function to execute the two different methods in one click.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Using the arrow method, only the first method gets called though - I can't get my console.log to print in _showResult – maddie Aug 27 '19 at 17:33
  • Both method will execute. Might be you are getting different errors. Can you please check your console logs. –  Aug 27 '19 at 17:37
0

you can use arrow function in action

<button  onClick={(event) => {
   this.computePiePercentages(); 
   this._showResults.bind(null, true);
}}>
Click me
</button>

or can you can make new method in component like

onBtnAction = (bool) => {
   this.computePiePercentages(); 
   this._showResults.bind(null, true);
}

and on OnClick call it

<button  onClick={this.onBtnAction}>Click me</button>
Olivier Boissé
  • 15,834
  • 6
  • 38
  • 56
Ahmed Nasser
  • 114
  • 6