B.Gees
B.Gees

Reputation: 1155

Multiple events to create a dynamic +/- editable input

I would like to create my own input[type="number"]. I try to create an input button which:

  1. Must allows the user to enter a value between 1 and 10 and if this is not the case, only a limit value (1 or 10).

  2. Must make it possible to increase or decrease the number entered using the + and - buttons.

CODEPEN

CURRENT LIMITATION: I tried to do it myself but I have difficulties to set up this input. 1) I don't know how to make sure that the value can be edited by the user and can also be modified using the +/- buttons. 2) I also don't know how to have the value automatically corrected when the _onChange event is requested.

HTML:

<div id="errors" style="
  background: #c00;
  color: #fff;
  display: none;
  margin: -20px -20px 20px;
  padding: 20px;
  white-space: pre-wrap;
"></div>
<div id="root"></div>
<script>
window.addEventListener('mousedown', function(e) {
  document.body.classList.add('mouse-navigation');
  document.body.classList.remove('kbd-navigation');
});
window.addEventListener('keydown', function(e) {
  if (e.keyCode === 9) {
    document.body.classList.add('kbd-navigation');
    document.body.classList.remove('mouse-navigation');
  }
});
window.addEventListener('click', function(e) {
  if (e.target.tagName === 'A' && e.target.getAttribute('href') === '#') {
    e.preventDefault();
  }
});
window.onerror = function(message, source, line, col, error) {
  var text = error ? error.stack || error : message + ' (at ' + source + ':' + line + ':' + col + ')';
  errors.textContent += text + '\n';
  errors.style.display = '';
};
console.error = (function(old) {
  return function error() {
    errors.textContent += Array.prototype.slice.call(arguments).join(' ') + '\n';
    errors.style.display = '';
    old.apply(this, arguments);
  }
})(console.error);
</script>

CSS:

body {
  font: 14px "Century Gothic", Futura, sans-serif;
  margin: 20px;
}

ol, ul {
  padding-left: 30px;
}

.board-row:after {
  clear: both;
  content: "";
  display: table;
}

.status {
  margin-bottom: 10px;
}

.square {
  background: #fff;
  border: 1px solid #999;
  float: left;
  font-size: 24px;
  font-weight: bold;
  line-height: 34px;
  height: 34px;
  margin-right: -1px;
  margin-top: -1px;
  padding: 0;
  text-align: center;
  width: 34px;
}

.square:focus {
  outline: none;
}

.kbd-navigation .square:focus {
  background: #ddd;
}

.game {
  display: flex;
  flex-direction: row;
}

.game-info {
  margin-left: 20px;
}

REACT JS:

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 5,
    };
    this._Plus = this._Plus.bind(this)
    this._Minus = this._Minus.bind(this)
    this._onChange = this._onChange.bind(this)
  }

  _Plus = () => {
    var val = this.state.count;
    if (val >= 10) {
      val = 10;
    } else if (val < 1) {
      val = 1;
    } else {
      val += 1;
    }
    this.setState({ count: val });
  }

  _Minus = () => {
    var val = this.state.count;
    if (val > 10) {
      val = 10;
    } else if (val <= 1) {
      val = 1;
    } else {
      val -= 1;
    }
    this.setState({ count: val });
  }

  _onChange = (e) => {
    var val = e.target.count;
    if (val > 10) {
      val = 10;
    } else if (val <= 1) {
      val = 1;
    }
    this.setState({ count: val });
  }

  render() {
    return (
      <div>
        <button onClick={this._Plus}>+</button>
        <input type="number" min = {1} max={10} defaultValue={5} value={this.state.count} onChange={this._onChange}/>
        <button onClick={this._Minus}>-</button>
      </div>
    );
  }
}

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

Upvotes: 0

Views: 32

Answers (1)

Ted
Ted

Reputation: 14927

I made a few tweaks, and put validation into the blur event, to allow the user to type any number, but have it restricted once they leave the input. Run the snippet below to see it work.

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 5,
    };
  }
  
  validate = (val) => {
    if(val < 1){
      return 1;
    }else if(val > 10){
      return 10;
    }else{
      return val;
    }
  }
  
  step = (val) =>{
    const count = this.validate(this.state.count + val);
    if(count !== this.state.count){
      this.setState({count});
    }
  }

  onChange = (e) => {
    this.setState({ count: +e.target.value });
  }
  
  onBlur = (e) => {
    const count = this.validate(+e.target.value);
    if(count !== this.state.count){
      this.setState({count});
    }
  }

  render() {
    return (
      <div>
        <button onClick={() => this.step(1)}>+</button>
        <input 
          type="number" 
          min={1} 
          max={10} 
          defaultValue={5} 
          value={this.state.count} 
          onChange={this.onChange}
          onBlur={this.onBlur}
        />
        <button onClick={() => this.step(-1)}>-</button>
      </div>
    );
  }
}

ReactDOM.render(
  <Counter />,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Upvotes: 1

Related Questions