In javascript input
has change
event that in case of type="number"
occures when either the input looses its focus or user uses step up or step down functionality, but not on the normal typing.
document.querySelector("input").addEventListener("change", e => {
console.log(e.type, e.target.value)
})
<input type="number" step="0.01"> <button> </button>
But when I'm using react, it replaces change
event by input
event which occurs on typing too:
function App() {
const [val, setVal] = React.useState("")
function onChange(e) {
console.log(e.type, e.nativeEvent.type, e.target.value)
setVal(e.target.value)
}
return <input type="number" step="0.01" value={val} onChange={onChange} />
}
ReactDOM.render(<App />, document.getElementById("app"))
<script crossorigin src="//unpkg.com/react@17/umd/react.production.min.js"></script>
<script crossorigin src="//unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
<span id="app"></span> <button> </button>
I need to handle normal change
event that does not occur on typing.
How can I do that in react?
PS: Button in the snippects is a place where you can tab to from the input
.
Yes, the "when typing as it causes problems with editing value" part does help a bit, though it seems a code smell to me, maybe an XY problem. Can you share how typing in the input causes problems when using
onChange
in the normal React way?
I didn't want to fully refuse using it, I just want to use both.
Here is an example with a problem:
- You can't use backspace in decimal part (except yeu entered more then 2 decimal digits)
- If using delete in decimal part, zero is added and cursor jumps to the end
- If current value is number is like
1.<cursor>20
and you type a digit, cursor jumps to the end - If current value is like
<cursor>1000.00
an you press delete, the number becomes0.00
- If you try to write in an empty input, after pressing the first digit it becomes like
7.00<cursor>
and it's very difficult to enter something like 7.23 - I'ts difficult to erase all value from the input as it becomes
0.00
until you select it all - I think, there's much more issues
function App() {
const [val, setVal] = React.useState("")
function onChange(e) {
console.log(e.type, e.nativeEvent.type, e.target.value)
setVal(e.target.value == +e.target.valueAsNumber.toFixed(2)
? e.target.valueAsNumber.toFixed(2)
: e.target.value
)
}
return <input type="number" step="0.01" value={val} onChange={onChange} />
}
ReactDOM.render(<App />, document.getElementById("app"))
<script crossorigin src="//unpkg.com/react@17/umd/react.production.min.js"></script>
<script crossorigin src="//unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
<span id="app"></span> <button> </button>
If I try to use onBlur
fpr formatting, it becomes better, but:
- The number is not formatted when you click step up or step down buttons or press up or down on the keybord with the same effect:
function App() {
const [val, setVal] = React.useState("")
function onChange(e) {
console.log(e.type, e.nativeEvent.type, e.target.value)
setVal(e.target.value)
}
function onBlur(e) {
console.log(e.type, e.nativeEvent.type, e.target.value)
if (e.target.value && e.target.value == +e.target.valueAsNumber.toFixed(2)) {
setVal(e.target.valueAsNumber.toFixed(2))
}
}
return <input type="number" step="0.01" value={val} onChange={onChange} onBlur={onBlur} />
}
ReactDOM.render(<App />, document.getElementById("app"))
<script crossorigin src="//unpkg.com/react@17/umd/react.production.min.js"></script>
<script crossorigin src="//unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
<span id="app"></span> <button> </button>
So I want to use change
that occures both on blur and steps.