I have a simple controlled input of type number like below.
<input type="number" value={+value} step={1} onChange={this.updateMyChange} />
My value
often returns a decimal number like 123.123
. My problem is, when I try edit the value. The cursor loses focus and shifts to the beginning ignoring the whole numbers as soon as the decimal places are cleared. Like below:
How do I address this? Immediately after the decimal places are cleared, the cursor jumps to the beginning thereby making it impossible to edit the whole numbers. Any help would be appreciated.
Update Below is the remaining code as requested by the user below.
render() {
const {value} = this.state;
return (
<input type="number" value={+value} step={1} onChange={this.updateMyChange} />
)
}
And my updateMyChange method is simply
updateMyChange(e) {
this.setState({ value: e.target.value });
}
It does nothing much simply sets the new value. The cursor position jumps to the end as soon as decimal places are cleared. It does not set cursor for whole numbers.
This is how React updates an input field's value:
node.setAttribute(attributeName, '' + value);
When you set value
attribute using that method, the caret goes to the beginning of the field, regardless of using React. You can see what I am saying in this fiddle - https://jsfiddle.net/5v896g3q/
(Just try and position the cursor in the field, between changes).
According to MDN, setAttribute
is unstable when dealing with value
. The recommended way of changing value
is by accessing the value
property of the element, like element.value = newValue
. If you use that approach, all seems to go as expected.
This is all I can tell for sure. Now let's speculate a little. When you type anything in that field, you are:
When you are typing on the field, step 3 is likely to have no impact, because when the value comes back, the input already got it right. Except on the case with the float number. When your field reads 1.
, the actual value React updates the field with is 1
. And React uses the evil method (setAttribute
).
So, a workaround I found was setting the value of the field, using the proper method, before React touches it, on componentWillUpdate
:
componentWillUpdate(nProps, nState){
this.refs.input.value = '0' + nState.value
}
The problem there, is that it is "numerizing" the value on every change, meaning I won't be able to have a point (1.
). For that reason, I will only edit the input in case new value is 2 characters shorter than the old one (point + digit after point):
componentWillUpdate(nProps, nState){
if(this.state.value.length - nState.value.length === 2){
this.refs.input.value = '0' + nState.value
}
}
Working example - https://jsfiddle.net/bsoku268/3/
note: the fiddle is for demonstration purposes, and not supposed to be a bulletproof solution, as there are many ways of interacting with an input field, such as copy & paste, drag & drop, autofill, etc
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With