I'm trying to create a currency input, that starts as something like
" $00.00"
and then when you start typing, it types the cents first, then moves on to the dollars (ie, updates the right side numbers first), e.g
" $00.50"
A reddit user posted this piece of JS code to help me : https://codepen.io/benjaminreid/pen/gRbgxK?editors=0010
const FormattedInput = class extends React.Component {
constructor(props) {
super(props);
this.amountChanged = this.amountChanged.bind(this);
this.state = {
value: 0,
};
}
amountChanged(e) {
this.setState({
value: e.target.value,
});
}
formatValue(value) {
return accounting.formatMoney(parseFloat(value) / 100);
}
render() {
return (
<div>
<label for="formatted">Formatted input</label>
<input
id="formatted"
type="text"
value={this.formatValue(this.state.value)}
/>
<label for="amount">Actual user input (type in here)</label>
<input
id="amount"
type="text"
onChange={this.amountChanged}
value={this.state.value}
/>
</div>
);
}
}
const App = () =>
<div>
<FormattedInput/>
</div>
;
ReactDOM.render(
<App/>,
document.querySelector('#app')
);
It works great, but the input you enter and the input that gets displayed are in two different boxes. I was wondering if there was a way to type straight into the formatted currency box?
Does anyone have a better solution perhaps? Help would be greatly appreciated.
I tried to code something to solve your problem. It is not so hard to build from scratch.
const FormattedInput = class extends React.Component {
constructor(props) {
super(props);
this.amountChanged = this.amountChanged.bind(this);
this.state = {
value: '',
rawValue: '',
};
}
amountChanged(e) {
let tmpAmount = '';
let tmpValue = e.target.value.slice(-1);
let newRawValue = this.state.rawValue + tmpValue;
if ( this.state.value.length > e.target.value.length) {
this.setState({
value: '',
rawValue: '',
})
}
else {
if (newRawValue.length === 1) {
tmpAmount = '0.0' + newRawValue;
}
else if (newRawValue.length === 2) {
tmpAmount = '0.' + newRawValue;
}
else {
let intAmount = newRawValue.slice(0, newRawValue.length - 2);
let centAmount = newRawValue.slice(-2);
tmpAmount = intAmount.replace(/\B(?=(\d{3})+(?!\d))/g, ",") + '.' + centAmount;
}
this.setState({
value: tmpAmount,
rawValue: newRawValue,
});
}
}
formatValue(value) {
return accounting.formatMoney(parseFloat(value) / 100);
}
render() {
return (
<div>
<label for="amount">Mix</label>
<input
id="amount"
type="text"
placeholder="$0.00"
onChange={this.amountChanged}
value={this.state.value}
/>
</div>
);
}
}
const App = () =>
<div>
<FormattedInput/>
</div>
;
ReactDOM.render(
<App/>,
document.querySelector('#app')
);
Related
Im trying to change the style whenever ReactSlider is changed. I want to add for example brightness when slider is increased in React. I did it but I cannot seem to get the styles to be added to the image whenever the slider goes through the onchange event. Here is the code:
import React, { Component } from 'react';
import { BsFileEarmarkPlus } from 'react-icons/bs';
import ReactSlider from 'react-slider';
class Edit extends React.Component {
constructor(props) {
super(props);
this.state = {
file: null,
}
this.ImageUpload = this.ImageUpload.bind(this);
this.ChangeImage = this.ChangeImage.bind(this);
}
ImageUpload(event) {
console.log(event.target.files[0]);
this.setState({
file: URL.createObjectURL(event.target.files[0]),
});
}
ChangeImage(props) {
console.log(props);
var amount = this.props + '%';
var imgStyles = {
filter: 'brightness(' + amount + ')'
}
}
render() {
return (
<div className="editor">
<h1>Editor</h1>
<label htmlFor="fileChoose"><BsFileEarmarkPlus />Upload
<input type="file" id="fileChoose" onChange={this.ImageUpload} />
</label>
<hr />
<div className="img-surround">
<img
src={this.state.file}
id="img"
style={imgStyles} />
</div>
<div className="edit-nav">
<ReactSlider
className="horizontal-slider"
defaultValue={0}
max={100}
min={-100}
thumbClassName="example-thumb"
trackClassName="example-track"
renderThumb={(props, state) => <div {...props}>{state.valueNow}</div>}
onChange={this.ChangeImage}
/>
</div>
</div>
);
}
}
export default Edit;
The only problem is imgStyles is undefined when called from outside the render(). Everything else works.
Because you defined 'imgStyles' variable in 'ChangeImage' function.
You should define this variable out of class or define it as state variable.
var imgStyles = {};
class Edit extends React.Component {
...
ChangeImage(props) {
console.log(props);
var amount = this.props + '%';
imgStyles = {
filter: 'brightness(' + amount + ')'
}
}
...
Or
...
constructor(props) {
super(props);
this.state = {
file: null,
imgStyles: {}
}
}
...
ChangeImage(props) {
console.log(props);
var amount = this.props + '%';
this.setState({ imgStyles: { filter: 'brightness(' + amount + ')' } });
}
...
<img
src={this.state.file}
id="img"
style={this.state.imgStyles} />
...
I am fairly new to React. Currently I have two React components - Article.js and ControlForm.js
My render return in Article.js is this:
return (
<div className="article">
{article_wrapper.map( article =>
<div key={article.node.nid} className="article-main-display">
<h1 className="title" dangerouslySetInnerHTML={createMarkup(article.node.title)}/>
<div className="img-div"><img src={article.node.field_image.src} /></div>
<ControlForm />
<div dangerouslySetInnerHTML={createMarkup(article.node.field_user_hsk_level)} />;
<div className="field-name-field-chinese">
<div dangerouslySetInnerHTML={createMarkup(article.node.chinese)} />;
</div>
</div>
)}
</div>
);
The ControlForm.js has several form elements (all of which I'd like to be able to pass along if need be), but this is the main one:
<div className="form-item form-type-select form-group">
<label className="control-label">Font Size</label>
<select
value={this.state.value}
onChange={this.handleSizeSelect}
id="font-size"
className="form-control form-select"
>
<option value="0">Small</option>
<option value="1">Normal</option>
<option value="2">Large</option>
<option value="3">XL</option>
</select>
</div>
I'd like to be able to set a class on one of the divs in the Article.js based on changing a value in the ControlForm.js
What is the most "React" way to do this? Would creating a common parent to both be the best method (right now, their only parent in common is the main App.js)
Sorry if I don't totally understand how this is supposed to work - this is my first React app.
The class associated with the components are ControlForm and withFetching respectively.
EDIT - the demo example below works, but I have some additional issues with how to integrate it properly into my existing code. Here's the existing functions of ControlForm:
class ControlForm extends Component {
constructor() {
super();
this.state = { toggleActive: false, sizeSelect: "0", speed: 1.3, volume: .6};
this.onToggle = this.onToggle.bind(this);
this.handleSpeedChange = this.handleSpeedChange.bind(this);
this.handleVolumeChange = this.handleVolumeChange.bind(this);
this.handleSizeSelect = this.handleSizeSelect.bind(this);
}
onToggle() {
this.setState({ toggleActive: !this.state.toggleActive });
}
handleSizeSelect(event) {
this.setState({ sizeSelect: event.target.value });
this.setState({font: 'large-font'});
parentMethod(event.target.value);
}
handlePlayClick(e) {
e.preventDefault();
voice.playButtonClick();
}
handlePauseClick(e) {
e.preventDefault();
voice.pauseButtonClick();
}
handleStopClick(e) {
e.preventDefault();
voice.stopButtonClick();
}
handleVolumeChange(event) {
console.log(event.target.value);
this.setState({ volume: event.target.value });
}
handleSpeedChange(event) {
console.log(event.target.value);
this.setState({ speed: event.target.value });
}
Articles looks like this:
const withFetching = (url) => (Comp) =>
class WithFetching extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
isLoading: false,
error: null,
dynamicClassName: "parentClass"
};
this.changeClassName = this.changeClassName.bind(this);
}
changeClassName(childData) {
this.setState({
dynamicClassName: childData
});
}
componentDidMount() {
this.setState({ isLoading: true });
fetch(url)
.then(response => {
if (response.ok) {
return response.json();
} else {
throw new Error('Something went wrong ...');
}
})
.then(data => this.setState({ data, isLoading: false }))
.catch(error => this.setState({ error, isLoading: false }));
}
render() {
//return "test";
return <Comp { ...this.props } { ...this.state } />
}
}
function createMarkup(html) {
return {__html: html};
}
function changeClassName(childData) {
console.log("GETS HERE!")
this.setState({
dynamicClassName: childData
});
}
const Articles = ({ data, isLoading, error }) => {
console.log(data);
console.log(isLoading);
const article_wrapper = data.nodes || [];
if (error) {
return <p>{error.message}</p>;
}
if (isLoading) {
return <p>Loading ...</p>;
}
return (
<div className="article">
{article_wrapper.map( article =>
<div key={article.node.nid} className="article-main-display">
<h1 className="title" dangerouslySetInnerHTML={createMarkup(article.node.title)}/>
<div className="img-div"><img src={article.node.field_image.src} /></div>
<ControlForm parentMethod={changeClassName} />
<div dangerouslySetInnerHTML={createMarkup(article.node.field_user_hsk_level)} />;
<div className="field-name-field-chinese">
<div dangerouslySetInnerHTML={createMarkup(article.node.chinese)} />;
</div>
</div>
)}
</div>
);
}
export default withFetching(API)(Articles);
Sorry about all of these questions, I know a lot of this is due to unfamiliarity with React - this is the first thing I've tried to build in React
You want to change parents from his childs.
First, you have to create a handler function at Article.js and pass it to ControlForm.js as a property.
<ControlForm changeDiv={this.changeDiv} />
Then you focus on ControlForm.js, whenever you want to happen, you just execute the function you passed as a the prop changeDiv, like this.props.changeDiv()
See also possible duplicate: How to update parent's state in React?
you can conditionally render a class based on state and your handler was missing the values from the event on the onChange
here's a demo of dynamically changing style base on the state
demo
Article.js ,
class Article extends React.Component {
constructor(props) {
super(props);
this.state = {
dynamicClassName: "parentClass"
}
this.changeClassName = this.changeClassName.bind(this);
}
changeClassName(childData) {
this.setState({
dynamicClassName: childData
});
}
// user dynamicClassName wherever u want .
return ( <
div className = "article" > {
article_wrapper.map(article =>
<
div key = {
article.node.nid
}
className = "article-main-display" >
<
h1 className = "title"
dangerouslySetInnerHTML = {
createMarkup(article.node.title)
}
/> <
div className = "img-div" > < img src = {
article.node.field_image.src
}
/></div >
<
ControlForm parentMethod={this.changeClassName} / >
<
div dangerouslySetInnerHTML = {
createMarkup(article.node.field_user_hsk_level)
}
/>; <
div className = "field-name-field-chinese" >
<
div dangerouslySetInnerHTML = {
createMarkup(article.node.chinese)
}
/>; < /
div > <
/div>
)
} <
/div>
);
}
In ControlForm js ,
class ControlForm extends React.Component {
constructor(props) {
super(props);
this.state = {
}
this.handleSizeSelect= this.handleSizeSelect.bind(this);
}
handleSizeSelect() {
this.props.parentMethod(this.state.value);
}
render() {
return (
<div className="form-item form-type-select form-group">
<label className="control-label">Font Size</label>
<select
value={this.state.value}
onChange={this.handleSizeSelect}
id="font-size"
className="form-control form-select"
>
<option value="0">Small</option>
<option value="1">Normal</option>
<option value="2">Large</option>
<option value="3">XL</option>
</select>
</div>
);
}
}
I have the following: (https://www.npmjs.com/package/react-sound)
return (
<div className = { "wrapper " + currentState.bgColor}>
<div className="wrapper-inner">
<CustomSound soundOn = { this.state.soundOn} />
<CorrectSound soundOn = { this.state.correct} />
<IncorrectSound soundOn = { this.state.incorrect} />
<h1 className = { isH1Visible}><span>the big</span> reveal</h1>
{form}
{cat}
{grid}
{timeUp}
{correct}
{incorrect}
</div>
</div>
)
the soundOn props for correct and incorrect is set inside "getAnswer" function:
import React, { Component } from 'react';
class Action1 extends Component {
constructor(props) {
super(props);
this.state = {
answer1: "",
answer2: "",
answer3: "",
answer4: "",
answerDisabled: false
}
}
updateStateProperty(el, val) {
var s = {};
s[el] = val;
this.setState(s);
}
getAnswer = (e) => {
let answer = e.target.getAttribute('data-id');
this.props.checkAnswer(e);
if(e.target.getAttribute('data-question') == ("option_" + this.props.question.correct_option)){
this.updateStateProperty(answer, 'correct');
this.props.setCorrectOn(true);
}
else {
this.updateStateProperty(answer, 'wrong');
this.props.setIncorrectOn(true);
}
this.setState({
answerDisabled: true
})
setTimeout(() => {
this.props.setIncorrectOn(false);
this.props.setCorrectOn(false);
this.updateStateProperty(answer, '');
}, 1000);
setTimeout(() => {
this.setState({
answerDisabled: false
})
}, 1500)
}
render() {
return(
<div className="action">
<div className={"action-question " + this.props.catBgColor}>
<h3>{this.props.question.question}</h3>
</div>
<div className={"action-answers " + this.props.catBgColor}>
<p className={this.state.answer1 + " " + (this.state.answerDisabled ? 'disable-link' : "")} data-id="answer1" data-question="option_1" onClick={this.getAnswer.bind(this)}>{this.props.question.option_1}</p>
<p className={this.state.answer2 + " " + (this.state.answerDisabled ? 'disable-link' : "")} data-id="answer2" data-question="option_2" onClick={this.getAnswer.bind(this)}>{this.props.question.option_2}</p>
<p className={this.state.answer3 + " " + (this.state.answerDisabled ? 'disable-link' : "")} data-id="answer3" data-question="option_3" onClick={this.getAnswer.bind(this)}>{this.props.question.option_3}</p>
<p className={this.state.answer4 + " " + (this.state.answerDisabled ? 'disable-link' : "")} data-id="answer4" data-question="option_4" onClick={this.getAnswer.bind(this)}>{this.props.question.option_4}</p>
</div>
</div>
);
}
}
export default Action1;
each sound component has the following structure (with different sound files):
import React from 'react';
import Sound from 'react-sound';
class CustomSound extends React.Component {
render() {
return (
<Sound
url="./assets/sound.mp3"
playStatus={this.props.soundOn ? Sound.status.PLAYING : Sound.status.STOPPED}
playFromPosition={0 /* in milliseconds */}
/>
);
}
}
export default CustomSound;
when either of the 2 is triggered:
this.props.setCorrectOn(true); or this.props.setIncorrectOn(true);
the sound coming from:
<CustomSound soundOn = { this.state.soundOn} />
stops and starts again. Ideally that is a soundtrack that I would like to carryon playing and stop it at a later stage of the game.
The problem seems to be happening on iPad only. On chrome on desktop is absolutely fine.
Solution found at: http://www.schillmania.com/projects/soundmanager2/doc/
soundManager.setup({ ignoreMobileRestrictions: true });
I'm trying to make if else statement to allow user to type only integer in TextArea but i have no idea how.
This is my code:
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
currencyValue: '',
currencyCode: 'USD',
result: ''
}
}
handleChangeCurrencyValue(event) {
console.log('qwer ' + this)
this.setState(Object.assign({}, this.state, {currencyValue: event.target.value}))
}
handleChangeCurrencyCode(event) {
console.log('qwer ' + this)
this.setState(Object.assign({}, this.state, {currencyCode: event.target.value}))
}
calculate(event){
var obj = this
axios.get('http://localhost:8080/Currency/currency?currencyCode=' + this.state.currencyCode + '¤cyValue=' + this.state.currencyValue + '&responseType=json')
.then(function(resp){
console.log('RESULT: ', resp.data.result)
obj.setState(Object.assign({}, obj.state, {result: resp.data.result}))
})
.catch(error => {
console.log(error)
});
}
render() {
return (
<div>
<TextArea functionChangeValue={this.handleChangeCurrencyValue.bind(this)} value={this.state.currencyValue} />
<ComboBox functionChangeCode={this.handleChangeCurrencyCode.bind(this)} value={this.state.currencyCode} />
<p>
<button onClick={this.calculate.bind(this)}>Calculate</button>
</p>
<div>{this.state.result}</div>
</div>
);
}
}
class TextArea extends React.Component {
render() {
return (
<div>
<h4>
<div>Type value you want to exchange: </div>
<input type='text' onChange={this.props.functionChangeValue}/>
{/* <div>Value of your currency is: {this.props.value}</div> */}
</h4>
</div>
);
}
}
class ComboBox extends React.Component {
render() {
return(
<div>
<h4>
<div>Select your currency:</div>
<select onChange={this.props.functionChangeCode}>
<option>USD</option>
<option>EUR</option>
<option>GBP</option>
</select>
{/* <div>Your currency is: {this.props.value}</div> */}
</h4>
</div>
);
}
}
export default App;
Can you give me idea or some example?
You can use regex and conditionally change state.
onChange(event){
const regex = /^[0-9\b]+$/;
const value = event.target.value;
if (value === '' || regex.test(value)) {
this.setState({ value })
}
}
Consider making use of the ValidatorJS Library as opposed to rolling your own validation method.
Example usage in your code would be something like this...
handleChangeCurrencyValue(event) {
console.log('qwer ' + this)
const currencyValue = event.target.value;
if(validator.isInt(currencyValue)) {
this.setState({ currencyValue });
}
}
I recommend using libraries that have been thoroughly tested for validation as this will reduce security concerns down the line. Also, validator is extremely easy to implement.
can it be something like that:
<input type="number" min="0" step="1"/>
You can use regex (regular expression) to handle that. The regex that you use is /[0-9]+/g.
For example you have input:
<input value={this.state.value} onChange={this.onChange}/>
And the onChange:
onChange(text) {
let newText = '';
const numbers = '^[0-9]';
for (let i = 0; i < text.length; i++) {
if (numbers.indexOf(text[i] > -1)) {
newText += text[i];
}
this.setState({ currencyValue: newText });
}
}
or like this:
onChange(e){
const re = /^[0-9\b]+$/;
if (e.target.value == '' || re.test(e.target.value)) {
this.setState({currencyValue: e.target.value})
}
}
May it can help you! :)
I have recently started working on react.js, while creating the login page I have used setstate method to set the value of userEmail to text box.
I have created a method which checks the validity of email address and I am calling it every time when user enters a new letter.
handleChangeInEmail(event) {
var value = event.target.value;
console.log("change in email value" + value);
if(validateEmailAddress(value) == true) {
this.setState(function() {
return {
showInvalidEmailError : false,
userEmailForLogin: value,
}
});
} else {
this.setState(function() {
return {
showInvalidEmailError : true,
userEmailForLogin: value
}
});
}
This method and userEmailForLogin state is passed in render method as
<EmailLoginPage
userEmailForLogin = {this.state.userEmailForLogin}
onHandleChangeInEmail= {this.handleChangeInEmail}
/>
I am using the method to validate the email address and the method is
validateEmailAddress : function(emailForLogin) {
if (/^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(emailForLogin)) {
return true;
}
return false;
},
I am using this method and state in render of EmailLoginPage as <input type="text" name="" placeholder="Enter Email" className="email-input-txt" onChange={props.onHandleChangeInEmail} value = {props.userEmailForLogin}/>
This is working fine in normal case , but when I try to input a large email addess say yjgykgkykhhkuhkjhgkghjkhgkjhghjkghjghghkghbghbg#gmail.com, it crashes
IMO the frequent change in state is causing this but I couldn't understand what should be done to get rid of this.
I think issue is with the regex only, i tried with other and it's working properly.
Instead of writing the if/else inside change function simply you are write it like this:
change(event) {
var value = event.target.value;
this.setState({
showInvalidEmailError : this.validateEmailAddress(value),
value: value,
});
}
Copied the regex from this answer: How to validate email address in JavaScript?
Check the working solution:
class App extends React.Component {
constructor(){
super();
this.state = {
value: '',
showInvalidEmailError: false
}
this.change = this.change.bind(this);
}
change(event) {
var value = event.target.value;
this.setState(function() {
return {
showInvalidEmailError : this.validateEmailAddress(value),
value: value,
}
});
}
validateEmailAddress(emailForLogin) {
var regex = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
if(regex.test(emailForLogin)){
return true;
}
return false;
}
render() {
return(
<div>
<input value={this.state.value} onChange={this.change}/>
<br/>
valid email: {this.state.showInvalidEmailError + ''}
</div>
);
}
}
ReactDOM.render(
<App/>,
document.getElementById("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>
<div id='app'/>
You could use Lodash's debounce function so that the check function is not called unless the user stops typing for x amount of time (300ms in my scenario below).
_this.debounceCheck = debounce((value) => {
if(validateEmailAddress(value)) {
this.setState(function() {
return {
showInvalidEmailError : false,
userEmailForLogin: value,
}
});
} else {
this.setState(function() {
return {
showInvalidEmailError : true,
userEmailForLogin: value
}
});
}
}, 300)
handleChangeInEmail(event) {
_this.debounce(event.target.value)
}
A solution using debounce. This way multiple setState can be reduced.
DEMO: https://jsfiddle.net/vedp/kp04015o/6/
class Email extends React.Component {
constructor (props) {
super(props)
this.state = { email: "" }
}
handleChange = debounce((e) => {
this.setState({ email: e.target.value })
}, 1000)
render() {
return (
<div className="widget">
<p>{this.state.email}</p>
<input onChange={this.handleChange} />
</div>
)
}
}
React.render(<Email/>, document.getElementById('container'));
function debounce(callback, wait, context = this) {
let timeout = null
let callbackArgs = null
const later = () => callback.apply(context, callbackArgs)
return function() {
callbackArgs = arguments
clearTimeout(timeout)
timeout = setTimeout(later, wait)
}
}