Reputation: 1201
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}/>
Upvotes: 102
Views: 404303
Reputation: 1
Instead of using type="number", you can use type="text" like this:
<input
type="text"
value={this.state.financialGoal}
onChange={(event) => {
const inputValue = event.target.value;
const sanitizedValue = inputValue.replace(/[^0-9]/g, '');
this.setState({ financialGoal: sanitizedValue });
}}
/>
This avoids issues with type="number", such as allowing invalid characters like e, -, or ..
Upvotes: 0
Reputation: 779
You can do as follow to allow only numbers, backspace, tab, enter, delete, and arrow keys
<input
type="text"
id="phone_number"
name="phone_number"
className="grow"
onKeyDown={(e) => {
if (!/[0-9]|Backspace|Tab|Enter|Delete|ArrowLeft|ArrowRight/.test(e.key)) {
e.preventDefault();
}
}}
/>
Upvotes: 2
Reputation: 128
<input
onKeyDown={(event) => {
const filter = ["Backspace", "ArrowRight", "ArrowLeft", "Tab"];
if (!/[0-9]/.test(event.key) && filter.indexOf(event.key) === -1) {
event.preventDefault();
}
}}
/>
Upvotes: 0
Reputation: 7059
If you want to handle both .
, ,
and
(nothing) for the input as a number then you can use this mix:
<input
type='number'
pattern='[0-9]+([\,|\.][0-9]+)?'
step='1'
value={this.state.financialGoal}
onChange={this.handleChange}
/>
The e.target.value
will be a string
that can then be parsed to float when needed (like when passed for back-end call). It means that the financialGoal
is still a number but should be in a string format.
Decimal value or no number is usually not handled well by default, so this way I have a controlled string input as a number.
class FinancialApp extends React.Component {
constructor(props) {
super(props)
this.state = {
financialGoal: '5,5'
}
this.handle
}
handleChange = (e) => {
this.setState({
financialGoal: e.target.value
})
console.log(`${e.target.validity.valid} ${this.state.financialGoal}`)
}
render() {
return ( <
div >
<
p > {
this.state.financialGoal
} < /p> <
input placeholder = 'finanical goal'
type = 'number'
pattern = '[0-9]+([\,|\.][0-9]+)?'
step = '1'
value = {
this.state.financialGoal
}
onChange = {
this.handleChange
}
/> <
/div>
)
}
}
ReactDOM.render( < FinancialApp / > , document.querySelector("#app"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="app"></div>
Upvotes: 1
Reputation: 21
Use a pattern validation in order to allow one point (for decimals) and not allow spaces. You need to pass an arrow function in setState() in order to immediately update the state value, once it will be placed back in the input field.
*considering a class component
Given some context to the state variable.
constructor(props) {
super(props);
this.state = {inputValue: ''};
};
The input field content is evaluated against the pattern
regex. If both match, the event's validity.valid
property is assigned as true
, otherwise false
:
<input
pattern = '[0-9]*\.?[0-9]*'
type = 'text'
value = {this.state.inputValue}
onChange = {this.handleChange}
...>
In handleChange
, the state is immediately updated if validity.valid
is true, otherwise it keeps the previous value (and the text in the input field doesn't change).
handleChange = (e) => {
this.setState((prevState) => (
e.target.validity.valid ? {inputValue: e.target.value} : prevState)
)
};
Upvotes: 2
Reputation: 309
handleChange(event) {
const value = event.target.value
let finalValue;
Number.isNaN(parseInt(value)) ? finalValue = 0 : finalValue = parseInt(value)
this.setState({financialGoal: finalValue});
}
Upvotes: 0
Reputation: 876
The fastest way I found was adding a onKeyPress like this:
<input
type="text"
name="example"
value="Type here"
onKeyPress={(event) => {
if (!/[0-9]/.test(event.key)) {
event.preventDefault();
}
}}
>
Upvotes: 5
Reputation: 1769
We can use the Terinary operator and do like this. Also using useState to set the values to the object
<input id="cost" name="cost" type="text" onChange = {e=>isNaN(e.target.value)?e.target.value="":setItem({...item,cost:parseInt(e.target.value)})} />
Upvotes: 1
Reputation: 204
I am using isNaN function of JS to verify whether it is number or not.
const handleChange2 = (e) => {
if (isNaN(e.target.value)) {
return;
}
const onlyNums = e.target.value.replace(/[^0-9]/g, "");
setFormData({
...formData,
[e.target.name]: onlyNums,
});
};
const [formData, setFormData] = useState({
name: "",
phone: "",
email: "",
address: "",
});
<input
value={phone}
onChange={(e) => handleChange2(e)}
placeholder="Phone"
type="text"
name="phone"
required
/>
Note:The value stored in the state will string, if you want it to be a number/int just use Number to convert it into integer. ex: let phone= Number(formData.phone)
Upvotes: 4
Reputation: 678
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;
}
};
Upvotes: 0
Reputation: 3860
Simply way in React
<input
onKeyPress={(event) => {
if (!/[0-9]/.test(event.key)) {
event.preventDefault();
}
}}
/>
Upvotes: 117
Reputation: 733
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.
Upvotes: 3
Reputation: 432
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.
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
/>
defaultValue
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.
Upvotes: 3
Reputation: 331
<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);
}
};
Upvotes: 2
Reputation: 9
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;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);
}
}}
/>
Upvotes: 0
Reputation: 19049
I tried to mimic your code and noticed that there's an issue on React with <input type='number' />
. For workaround, check this example and try it yourself: https://codepen.io/zvona/pen/WjpKJX?editors=0010
You need to define it as normal input (type='text') with pattern for numbers only:
<input type="text" pattern="[0-9]*"
onInput={this.handleChange.bind(this)} value={this.state.financialGoal} />
And then to compare the validity of input:
const financialGoal = (evt.target.validity.valid) ?
evt.target.value : this.state.financialGoal;
The biggest caveat on this approach is when it comes to mobile --> where keyboard isn't in numeric but in normal alphabetic format.
Upvotes: 80
Reputation: 115
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.
Upvotes: -4
Reputation: 482
2019 Answer Late, but hope it helps somebody
This will make sure you won't get null on an empty textfield
// 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>
);
};
Upvotes: 1
Reputation: 10825
The most effective and simple solution I found:
<input
type="number"
name="phone"
placeholder="Phone number"
onKeyDown={e => /[\+\-\.\,]$/.test(e.key) && e.preventDefault()}
/>
Upvotes: 3
Reputation: 1951
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
Upvotes: 0
Reputation: 109
Today I find use parseInt()
is also a good and clean practice. A onChange(e)
example is below.
onChange(e){
this.setState({[e.target.id]: parseInt(e.target.value) ? parseInt(e.target.value) : ''})
}
parseInt()
would return NaN
if the parameter is not a number.parseInt('12a')
would return 12.Upvotes: 9
Reputation: 722
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!
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
Upvotes: 27
Reputation: 29
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
Upvotes: -1
Reputation: 815
one line of code
<input value={this.state.financialGoal} onChange={event => this.setState({financialGoal: event.target.value.replace(/\D/,'')})}/>
Upvotes: 63
Reputation: 93163
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();
}
const {Component} = React;
class Input extends Component {
onKeyPress(event) {
const keyCode = event.keyCode || event.which;
const keyValue = String.fromCharCode(keyCode);
if (/\+|-/.test(keyValue))
event.preventDefault();
}
render() {
return (
<input style={{width: '150px'}} type="number" onKeyPress={this.onKeyPress.bind(this)} />
)
}
}
ReactDOM.render(<Input /> , document.querySelector('#app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<section id="app"></section>
Upvotes: 24