[javascript] Only numbers. Input number in React

I'm trying to exclude minus and plus from input, but it's going wrong:

handleChange(event) {
  const value = event.target.value.replace(/\+|-/ig, '');
  this.setState({financialGoal: value});
}

Render input code:

<input style={{width: '150px'}} type="number" value={this.state.financialGoal} onChange={this.handleChange}/>

This question is related to javascript regex reactjs

The answer is


You can try this solution, since onkeypress will be attached directly to the DOM element and will prevent users from entering invalid data to begin with.

So no side-effects on react side.

<input type="text" onKeyPress={onNumberOnlyChange}/>

const onNumberOnlyChange = (event: any) => {
    const keyCode = event.keyCode || event.which;
    const keyValue = String.fromCharCode(keyCode);
    const isValid = new RegExp("[0-9]").test(keyValue);
    if (!isValid) {
       event.preventDefault();
       return;
    }
};

Maybe, it will be helpful for someone
Recently I used this solution for my App
I am not sure that is a correct solution but it works fine.

this.state = {
    inputValue: "",
    isInputNotValid: false
}

handleInputValue = (evt) => {
    this.validationField(evt, "isInputNotValid", "inputValue");
}

validationField = (evt, isFieldNotValid, fieldValue ) => {
   if (evt.target.value && !isNaN(evt.target.value)) {
        this.setState({ 
            [isFieldNotValid]: false,
            [fieldValue]: evt.target.value,
        });
    } else {
        this.setState({ 
            [isFieldNotValid]: true,
            [fieldValue]: "",
        });
    }
}

<input className={this.state.isInputNotValid ? "error" : null} type="text" onChange="this.handleInputValue" />

The main idea, that state won't update till the condition isn't true and value will be empty.
Don't need to use onKeyPress, Down etc.,
also if you use these methods they aren't working on touch devices


If you want to maintain input type='number' (probably for mobile devices to trigger the numeric keyboard) you should use onInput instead of onChange to capture your event changes.

Using onInput fixed a bug where typing text into a number input would bypass the validation I had assigned to it in onChange. Once I fixed this function to be called in onInput it triggered in all instances.

Here's an example of what I'm doing:

<input
    type='number'
    id={`player${index}Score`}
    className='form-control'
    pattern='[0-9]{0,5}'
    onInput={(event) => this.enterScore(event, index)}
    value={this.props.scoreLabel(this.state.scores[index])}
/>

I hope this helps!

EDIT - 08-03-2018:

I came up with a better solution. Use type='tel' along with a pattern regex within the input component itself.

The nuts and bolts of how I wired this up is here:

class Input extends React.Component {
  state = {message: '3'};

  updateNumber = (e) => {
    const val = e.target.value;
    // If the current value passes the validity test then apply that to state
    if (e.target.validity.valid) this.setState({message: e.target.value});
    // If the current val is just the negation sign, or it's been provided an empty string,
    // then apply that value to state - we still have to validate this input before processing
    // it to some other component or data structure, but it frees up our input the way a user
    // would expect to interact with this component
    else if (val === '' || val === '-') this.setState({message: val});
  }

  render() {
    return (
      <input
        type='tel'
        value={this.state.message}
        onChange={this.updateNumber}
        pattern="^-?[0-9]\d*\.?\d*$"
      />
    );
  }
}

ReactDOM.render(<Input />, document.getElementById('main'));

I have an example of this working on Codepen here


Set class on your input field:

$(".digitsOnly").on('keypress',function (event) {
    var keynum
    if(window.event) {// IE8 and earlier
       keynum = event.keyCode;
    } else if(event.which) { // IE9/Firefox/Chrome/Opera/Safari
       keynum = event.which;
    } else {
       keynum = 0;
    }

    if(keynum === 8 || keynum === 0 || keynum === 9) {
        return;
    }
    if(keynum < 46 || keynum > 57 || keynum === 47) {
        event.preventDefault();
    } // prevent all special characters except decimal point
}

Restrict paste and drag-drop on your input field:

$(".digitsOnly").on('paste drop',function (event) {
    let temp=''
    if(event.type==='drop') {
        temp =$("#financialGoal").val()+event.originalEvent.dataTransfer.getData('text');
        var regex = new RegExp(/(^100(\.0{1,2})?$)|(^([1-9]([0-9])?|0)(\.[0-9]{1,2})?$)/g); //Allows only digits to be drag and dropped
        if (!regex.test(temp)) {
           event.preventDefault();
           return false;
        }
    } else if(event.type==='paste') {
        temp=$("#financialGoal").val()+event.originalEvent.clipboardData.getData('Text')
        var regex = new RegExp(/(^100(\.0{1,2})?$)|(^([1-9]([0-9])?|0)(\.[0-9]{1,2})?$)/g); //Allows only digits to be pasted
        if (!regex.test(temp)) {
           event.preventDefault();
           return false;
        }
    }
}

Call these events in componentDidMount() to apply the class as soon as the page loads.


The most effective and simple solution I found:

<input
    type="number"
    name="phone"
    placeholder="Phone number"
    onKeyDown={e => /[\+\-\.\,]$/.test(e.key) && e.preventDefault()}
/>

Simply way in React

<input
      onKeyPress={(event) => {
        if (!/[0-9]/.test(event.key)) {
          event.preventDefault();
        }
      }}
    />

  • To stop typing, use onKeyPress not onChange .

  • Using event.preventDefault() inside onKeyPress means STOP the pressing event .

  • Since keyPress handler is triggered before onChange, you have to check the pressed key (event.keyCode), NOT the current value of input (event.target.value)

    onKeyPress(event) {
      const keyCode = event.keyCode || event.which;
      const keyValue = String.fromCharCode(keyCode);
      if (/\+|-/.test(keyValue))
        event.preventDefault();
    }
    

Demo below

_x000D_
_x000D_
const {Component} = React; _x000D_
_x000D_
class Input extends Component {_x000D_
  _x000D_
_x000D_
  onKeyPress(event) {_x000D_
   const keyCode = event.keyCode || event.which;_x000D_
   const keyValue = String.fromCharCode(keyCode);_x000D_
    if (/\+|-/.test(keyValue))_x000D_
      event.preventDefault();_x000D_
  }_x000D_
  render() {_x000D_
  _x000D_
   return (_x000D_
   <input style={{width: '150px'}} type="number" onKeyPress={this.onKeyPress.bind(this)} />_x000D_
_x000D_
   )_x000D_
  }_x000D_
 _x000D_
}_x000D_
_x000D_
ReactDOM.render(<Input /> , document.querySelector('#app'));
_x000D_
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>_x000D_
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>_x000D_
_x000D_
<section id="app"></section>
_x000D_
_x000D_
_x000D_


Here's my solution of plain Javascript

Attach a keyup event to the input field of your choice - id in this example.
In the event-handler function just test the key of event.key with the given regex.

In this case if it doesn't match we prevent the default action of the element - so a "wrong" key-press within the input box won't be registered thus it will never appear in the input box.

  let idField = document.getElementById('id');

  idField.addEventListener('keypress', function(event) {
    if (! /([0-9])/g.test(event.key)) {
      event.preventDefault();
    }
  });

The benefit of this solution may be its flexible nature and by changing and/or logically chaining regular expression(s) can fit many requirements. E.g. the regex /([a-z0-9-_])/g should match only lowercase English alphanumeric characters with no spaces and only - and _ allowed.

Note: that if you use /[a-z]/gi (note the i at the end) will ignore letter case and will still accept capital letters.


Solution

Today I find use parseInt() is also a good and clean practice. A onChange(e) example is below.

Code

onChange(e){
    this.setState({[e.target.id]: parseInt(e.target.value) ? parseInt(e.target.value) : ''})
}

Explanation

  1. parseInt() would return NaN if the parameter is not a number.
  2. parseInt('12a') would return 12.

 <input
        className="input-Flied2"
        type="TEXT"
        name="userMobileNo"
        placeholder="Moble No"
        value={phonNumber}
        maxLength="10"
        onChange={handleChangeInput}
        required
      />

  const handleChangeInput = (e) => {
const re = /^[0-9\b]+$/; //rules
if (e.target.value === "" || re.test(e.target.value)) {
  setPhoneNumber(e.target.value);
}

};


Define an input with an onChange() method like below (in my case, childState contains the state, passed down to this child component).

<input
   ...
   value={this.props.childState.volume}
   ...
   onChange={(e) => handleChangeInteger(e, {volume: e.target.value})}
/>

One approach I used was to install validatorJS (npm install validator --save)

I then defined a function handleChangeInteger, which takes an object that will be used to change your state, in this case, {volume: e.target.value}. Note: I needed the OR condition to allow my input to be blank, otherwise it would not let the user backspace (delete) the last integer if they wanted the field blank.

const handleChangeInteger = (e, obj_to_return) => {
  if (validator.isInt(e.target.value) || e.target.value == '') {
    this.props.childSetState(obj_to_return)
  }
}

The user will now not be allowed to type anything other than backspace, 0-9, or e (this is a number..) in the input field.

I referenced this post to create my solution: https://stackoverflow.com/a/45676912/6169225


one line of code

<input value={this.state.financialGoal} onChange={event => this.setState({financialGoal: event.target.value.replace(/\D/,'')})}/>

After reading all the answers but none really working for numbers only with copy and paste I came up with this solution.

  • parseInt solution: fails as parseInt("2a") is valid;
  • onKeyup sulution: fails on copy and paste, backspace;
  • key.which solution: will probably fail on copy and paste;
  • type="number" solution: fails on long numbers as javascript converts 40817810000000023511 into 40817810000000023500 because it is 53 bit language
<input
    name="address.line1"
    value={values.address.line1}
    onChange={(event: any) => {
      if (isFinite(event.target.value)) {
      // UPDATE YOUR STATE (i am using formik)
      setFieldValue("address.line1", event.target.value);
    }
  }}
/>

Here is a solution with onBlur, it can be very helpful as it also allows you to format the number the way you need it without requiring any black magic or external library.

2020 React Hooks

const toNumber = (value: string | number) => {
    if (typeof value === 'number') return value
    return parseInt(value.replace(/[^\d]+/g, ''))
}

const formatPrice = (price: string | number) => {
  return new Intl.NumberFormat('es-PY').format(toNumber(price))
}
<input
    defaultValue={formatPrice(price)}
    onBlur={e => {
      const numberValue = toNumber(e.target.value)
      setPrice(numberValue)
      e.target.value = formatPrice(numberValue)
    }}
    type='tel'
    required
/>

How it works:

  • Set initial value via defaultValue
  • Allow user to freely type anything they feel
  • onBlur (once the input looses focus):
    • replace any character that is not a digit with an empty string
    • setState() or dispatch() to manage state
    • set the value of the input field to the numeric value and apply optional formatting

Pay attention: In case your value come from a async source (e.g. fetch): Since defaultValue will only set the value on the first render, you need to make sure to render the component only once the data is there.


2019 Answer Late, but hope it helps somebody

This will make sure you won't get null on an empty textfield

  • Textfield value is always 0
  • When backspacing, you will end with 0
  • When value is 0 and you start typing, 0 will be replaced with the actual number
// This will make sure that value never is null when textfield is empty

const minimum = 0;   

export default (props) => {
    const [count, changeCount] = useState(minimum);

    function validate(count) {
        return parseInt(count) | minimum
    }

    function handleChangeCount(count) {
        changeCount(validate(count))
    }

    return (
        <Form>
            <FormGroup>
                <TextInput
                    type="text"
                    value={validate(count)}
                    onChange={handleChangeCount}
                />
            </FormGroup>
            <ActionGroup>
                <Button type="submit">submit form</Button>
            </ActionGroup>
        </Form>
    );
};

Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to regex

Why my regexp for hyphenated words doesn't work? grep's at sign caught as whitespace Preg_match backtrack error regex match any single character (one character only) re.sub erroring with "Expected string or bytes-like object" Only numbers. Input number in React Visual Studio Code Search and Replace with Regular Expressions Strip / trim all strings of a dataframe return string with first match Regex How to capture multiple repeated groups?

Examples related to reactjs

Error: Node Sass version 5.0.0 is incompatible with ^4.0.0 TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received type undefined raised when starting react app Template not provided using create-react-app How to resolve the error on 'react-native start' Element implicitly has an 'any' type because expression of type 'string' can't be used to index Invalid hook call. Hooks can only be called inside of the body of a function component How to style components using makeStyles and still have lifecycle methods in Material UI? React Hook "useState" is called in function "app" which is neither a React function component or a custom React Hook function How to fix missing dependency warning when using useEffect React Hook? Unable to load script.Make sure you are either running a Metro server or that your bundle 'index.android.bundle' is packaged correctly for release