I have the following react ponent:
var App = React.createClass({
getInitialState: function() {
return {value: 4.5}
},
change: function(event) {
this.setState({value: parseFloat(event.target.value)});
},
render: function() {
return <input type="number" value={this.state.value} onChange={this.change}/>;
}
});
React.render(<App/>, document.body);
You can see it here: /
The problem is that if I want to type in a number like: "4.7". When the user enters, "4.", it bees "4", due to being converted to a float in back. But this interrupts what the user was typing. What's the remended way of solving this problem?
I have the following react ponent:
var App = React.createClass({
getInitialState: function() {
return {value: 4.5}
},
change: function(event) {
this.setState({value: parseFloat(event.target.value)});
},
render: function() {
return <input type="number" value={this.state.value} onChange={this.change}/>;
}
});
React.render(<App/>, document.body);
You can see it here: http://jsfiddle/2hauj2qg/
The problem is that if I want to type in a number like: "4.7". When the user enters, "4.", it bees "4", due to being converted to a float in back. But this interrupts what the user was typing. What's the remended way of solving this problem?
Share Improve this question asked Dec 23, 2014 at 3:01 Winston EwertWinston Ewert 45.1k10 gold badges69 silver badges86 bronze badges4 Answers
Reset to default 5As imjared mentioned, it's because you're using parseFloat
this.setState({value: parseFloat(event.target.value)});
Instead, you may wish to only allow digits and the decimal. It stays stored as a string and never changes their input, but they're prevented from typing things like letters and spaces.
var nonNumericRegex = /[^0-9.]+/g;
this.setState({value: event.target.value.replace(nonNumericRegex, "")});
To allow negative numbers you need to do this:
this.setState({
value: event.target.value
.replace(nonNumericRegex, "")
.replace(/^(-.*?)-/g, "$1")
});
To enforce a leading dollar sign and no more than two decimals, and if the first character (after the $) is the decimal, prefix it with 0.
this.setState({
value: "$" + event.target.value
.replace(nonNumericRegex, "")
.replace(/(\.\d\d)\d+/g, "$1")
.replace(/^\./g, "0.")
})
Remove the parseFloat and your string won't be cast to a number?
change: function(event) {
this.setState({value: event.target.value});
}
http://jsfiddle/2hauj2qg/1/
If it doesn't make sense to do anything with the number until they're done typing and you follow the standard way of raising an event to signal changed data, you can acplish it with the following:
var MyComponent = React.createClass({
getInitialState: function() {
return {value: 4.5};
},
change: function(event) {
this.setState({value: event.target.value});
},
blur: function(event) {
this.props.onChange({value: parseFloat(event.target.value)});
},
render: function() {
return <input type="number" value={this.state.value} onBlur={this.blur} onChange={this.change}/>;
}
});
React.render(<MyComponent/>, document.body);
It doesn't make too much sense in this isolated example, but if you assume someone is using MyComponent and that they give it an onChange callback, then this works nicely. You get the benefits of a native input control but still return (through the callback) the number as an actual float.
What about writing a small ponent that will handle string values and pass only legal float values to the listeners ?
class NumberInput extends React.Component<{ onChange: (n: number) => void, value: number }, { value: number }> {
constructor(props: { onChange: ((n: number) => void); value: number }, context: any) {
super(props, context);
this.state = {
value: props.value || 0
};
}
handleInputChange = (e) => {
const value = e.target.value;
this.setState({
value: value
});
if (this.props.onChange) {
const floatValue = parseFloat(value);
if (!isNaN(floatValue)) {
this.props.onChange(floatValue)
}
}
};
ponentWillReceiveProps(newProps) {
this.setState({
value: newProps.value
})
}
render() {
return (
<Input step="0.1" value={this.state.value} onChange={this.handleInputChange} type="number"/>
)
}
}