Transfer between cents and dollars in html input in React

I'm a little weird, I'm dealing with currency in my application. On the model side, I save the currency as cents before sending it to the server, since I do not want to deal with decimal points on the server side. However, I want the normal currency displayed, not cents.

So, I have this input field, where I take data from dollars and change them to cents:

<input name="balance" type="number" step="0.01" min="0" placeholder="Balance in cents" onChange={this.handleUpdate} value={this.props.user.balance / 100)} /> 

And when there is a change in the input value, I change it back to cents before sending it upstream:

 handleUpdate: function(e) { var value = e.target.value; // changing it back from cents to dollars value = parseFloat(value) * 100; // save back to the parent component managing the prop this.props.onUserUpdate(value); } 

This baffles me, so I don’t have to enter a decimal point. "Let me demonstrate:

  • 33 in the input field β†’ becomes 3300 in the parent state β†’ returns as 33 in the prop component - everything is fine

  • 33.3 in the input field β†’ becomes 3330 in the parent state β†’ returns as 33.3 in the prop component - all is good

  • 33. in the input field β†’ becomes 3300 in the parent state β†’ returns as 33 in the prop component - this is the problem

As you can see in case 3, when the user first enters "." . it does not translate to the same number using "."

Since this is a controlled input, there is basically no way to write "."

I tried using an uncontrolled element with defaultValue , but the quantity support is not ready by the time the component is displayed, so it's just empty.

http://jsfiddle.net/fpbhu1hs/

+7
javascript reactjs
source share
2 answers

Managed inputs using derived values ​​can be complex - if you need to display invalid or otherwise strange input, then ...

  • always hold the value input in your own state component

     <input value={this.state.value} onChange={this.handleUpdate} // rest as above... 
  • get initial value in getInitialState()

     getInitialState: function() { return {value: this.props.user.balance / 100} } 
  • implement componentWillReceiveProps(nextProps) to determine when the prop value changes from above and re-displays the state value

     componentWillReceiveProps: function(nextProps) { if (this.props.user.balance != nextProps.user.balance) { this.setState({value: nextProps.user.balance / 100}) } } 

Now when the user enters β€œ33.”, you save your literal input with setState() , and then go to the parent.

 handleUpdate: function(e) { var value = e.target.value this.setState({value: value}) this.props.onUserUpdate(parseFloat(value) * 100) } 

If the value that the parent then returns to the child using props has not changed ( 3300 == 3300 in this case), then componentWillReceiveProps() do nothing.

Working fragment:

 <script src="http://fb.me/react-with-addons-0.12.2.js"></script> <script src="http://fb.me/JSXTransformer-0.12.2.js"></script> <div id="example"></div> <script type="text/jsx;harmony=true">void function() { 'use strict'; var Parent = React.createClass({ getInitialState() { return {cents: 3300} }, _changeValue() { this.setState({cents: Math.round(Math.random() * 2000 + Math.random() * 2000)}) }, _onCentsChange(cents) { this.setState({cents}) }, render() { return <div> <p><strong>Cents:</strong> {this.state.cents.toFixed(0)} <input type="button" onClick={this._changeValue} value="Change"/></p> <Child cents={this.state.cents} onCentsChange={this._onCentsChange}/> </div> } }) var Child = React.createClass({ getInitialState() { return {dollars: this.props.cents / 100} }, componentWillReceiveProps(nextProps) { if (this.props.cents != nextProps.cents) { this.setState({dollars: nextProps.cents / 100}) } }, _onChange(e) { var dollars = e.target.value this.setState({dollars}) if (!isNaN(parseFloat(dollars)) && isFinite(dollars)) { this.props.onCentsChange(parseFloat(dollars) * 100) } }, render() { return <div> <input type="number" step="0.01" min="0" value={this.state.dollars} onChange={this._onChange}/> </div> } }) React.render(<Parent/>, document.querySelector('#example')) }()</script> 
+10
source share

I use this simple solution to handle managed inputs and decimal values.

  • Create two details in your state, one to store the actual value, and the other to store the string.

     constructor(props) { .... this.state = { myProperty: 1.42, myPropertyString: '1.42' } } 
  • Set your input value String one

     <input type="text" onChange={this.handleUpdate} value={this.state.myPropertyString}/> 
  • The handleUpdate method updates both state variables.

     handleUpdate(e) { this.setState({ myProperty: parseFloat(e.target.value), myPropertyString: e.target.value }); } 
0
source share

All Articles