Michael Connor
Michael Connor

Reputation: 37

reactjs onChange not picking up last character

I can not figure out why my onChange event listener is not accepting the last character in my form. (See image and console.log) onChange Issue

I have read the article on the react website on forms https://reactjs.org/docs/forms.html and I have also looked at the post onChange in React doesn't capture the last character of text

but still can not seem to find the answer.

Here is my code:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';



/*stop clicking ability after clicking a problem (prevent default) and enable it when submit is done.*/

/*  let btnStyle = {
        backgroundColor: 'green'
    } */

/*we also changed onClick={() => props.onClick()} to just onClick={props.onClick},
 as passing the function down is enough for our example. Note that onClick={props.onClick()}
 would not work because it would call props.onClick immediately instead of passing it down.*/

class  Square extends React.Component
{
    render()
    {
        return (
                 <button className="square" onClick = {this.props.onClick} style = {{backgroundColor: this.props.backgroundColor}}>
                    {this.props.value}
                    {this.props.txt}
                </button>
            );
    }

}

class Board extends React.Component
{
    constructor(props)
    {
    super(props);
    this.state =
    {
      squares: Array(25).fill(null),
      xIsNext: true,
      squaresColor: Array(25).fill('null'),
      num1: generateRandomNumber(),
      num2: generateRandomNumber(),
      ans:  function(a,b){return(a * b);},
      sqTxt: Array(25).fill(null)
    };

    //this.handleAnswer = this.handleAnswer.bind(this);

  }

  handleClick(i)
  {
    const squares = this.state.squares.slice();           // makes a mutable copy of the array
    const squaresColor = this.state.squaresColor.slice(); // makes a mutable copy of the array
    const sqTxt = this.state.sqTxt.slice(); // makes a mutable copy of the array
    if (/* calculateWinner(squares) || */ squares[i])
    {
      return;
    }

    squaresColor[i] = 'blue';
    sqTxt[i] =  <input onChange = {(e,i) => this.handleAnswer(e, i)} className = 'answer-input' type = 'text' name = 'answer' />;


    this.setState({
                    squares:      squares,
                    xIsNext:      !this.state.xIsNext,
                    squaresColor: squaresColor,
                    /* num1:          generateRandomNumber(),
                    num2:         generateRandomNumber(), */
                    sqTxt:        sqTxt
                  });

    squares[i] = this.state.num1 + ' X ' + this.state.num2;
  }


  /*When an event is invoked, it will be passed an event object as it's first argument. You can name evt whatever you like. Common names are e evt and event.*/
  handleAnswer(e, i)
  {
      const userAnswer = parseInt(e.target.value, 10);
      const num1 = this.state.num1;
      const num2 = this.state.num2;
      const correctAnswer = num1 *  num2;
      const squaresColor = this.state.squaresColor.slice();           // makes a mutable copy of the array      

        console.log('num1: ' + num1);
        console.log('num2: ' + num2);
        console.log('userAnswer: ' + userAnswer);
        console.log('correctAnswer: ' + correctAnswer)

        squaresColor[i] = 'purple';


    this.setState({
                    squaresColor: squaresColor
                  })


      if(userAnswer === correctAnswer)
      {
          this.setState({squaresColor: squaresColor});
          console.log('correct');
          squaresColor[i] = 'green';
      }

      else
      {
          console.log('incorrect');
      }

      //create new numbers for next problem
      this.setState({num1: generateRandomNumber(), num2: generateRandomNumber()});
  }



  renderSquare(i)
  {
    return (
      <Square
        value={this.state.squares[i]}
        onClick = {() => this.handleClick(i)}
        backgroundColor = {this.state.squaresColor[i]}
        txt = {this.state.sqTxt[i]}
      />
    );
  }

  render()
  { 
    return (
      <div className = 'all-rows'>
        <div className="board-row">
          {this.renderSquare(0)}
          {this.renderSquare(1)}
          {this.renderSquare(2)}
          {this.renderSquare(3)}
          {this.renderSquare(4)}
        </div>
        <div className="board-row">
          {this.renderSquare(5)}
          {this.renderSquare(6)}
          {this.renderSquare(7)}
          {this.renderSquare(8)}
          {this.renderSquare(9)}
        </div>
        <div className="board-row">
          {this.renderSquare(10)}
          {this.renderSquare(11)}
          {this.renderSquare(12)}
          {this.renderSquare(13)}
          {this.renderSquare(14)}
        </div>
        <div className="board-row">
          {this.renderSquare(15)}
          {this.renderSquare(16)}
          {this.renderSquare(17)}
          {this.renderSquare(18)}
          {this.renderSquare(19)}
        </div>
        <div className="board-row">
          {this.renderSquare(20)}
          {this.renderSquare(21)}
          {this.renderSquare(22)}
          {this.renderSquare(23)}
          {this.renderSquare(24)}
        </div>
      </div>
    );
  }
}


class Game extends React.Component
{
  render() {
    return (
      <div className="game">
        <div className="gxame-board">
          <Board />
        </div>
        <div className="game-info">
        </div>
      </div>
    );
  }
}


ReactDOM.render(
  <Game />,
  document.getElementById('root')
);


function generateRandomNumber()
{
    return Math.floor(Math.random() * 10);
}

Upvotes: 1

Views: 3099

Answers (1)

Abid Rakhmansyah
Abid Rakhmansyah

Reputation: 966

The problem is you're using onChange. onChange mean that if you change something it'll send an event. For example in your code:
You've change input to 18, but the first input change was 1 before you type the next 8, so when you type 18, it will send 2 event onChange
And in the last line of handleAnswer, your code:

this.setState({num1: generateRandomNumber(), num2: generateRandomNumber()})

It means, after you've input 1 the state of num 1 & num 2 are changed.
I suggest to you that, you have to move this.setState({num1: generateRandomNumber(), num2: generateRandomNumber()}); in the conditional if, when user have input a right answer, it will change the state of num1 & num2.
Another suggestion from me, you can try this method
to call onChange event after pressing Enter key

Upvotes: 1

Related Questions