Get input value on Click in React - javascript

I'm trying to get the value of input onClick(not onChange) and I got really confused.
(the function should take user input and multiply it by 5)
var Multiply = React.createClass({
getInitialState: function(){
return {number: '-'}
},
multiply: function(a){
return (a * 5);
},
handleChange: function(e) {
this.setState({ number: e.target.value });
},
handleClick: function(e) {
this.multiply(this.state.number);
},
render: function () {
return (
<div>
<p>multiply by 5!</p><br />
<textarea onChange={this.handleChange}>
</textarea><br/>
<button onClick={this.handleClick}>Submit</button>
<p>result:</p> {this.state.result}
</div>
);
}
});
ReactDOM.render(
<Multiply/>,
document.getElementById('root')
);
Here is a link to code:
http://codepen.io/polinaz/pen/MmezZy?editors=0010
What's wrong with my logic? Will really appreciate a good explanation!
Thank you

When you click the button, it multiples the number by 5, but then you don't do anything with that multiplied number (the result). In your handleClick function you need something like this:
handleClick: function(e) {
this.setState({result: this.multiply(this.state.number)});
}

I added result to the state, and added a result variable into the multiply function so you can store it in the state. Please look below:
var Multiply = React.createClass({
getInitialState: function(){
//added result to the initial state here
return {number: '-',
result: 0}
},
multiply: function(a){
//added result var here, and set the state to accept this result
var result = a * 5;
this.setState({result: result});
},
handleChange: function(e) {
this.setState({ number: e.target.value });
},
handleClick: function(e) {
this.multiply(this.state.number);
},
render: function () {
return (
<div>
<p>multiply by 5!</p><br />
<textarea onChange={this.handleChange}>
</textarea><br/>
<button onClick={this.handleClick}>Submit</button>
<p>result:</p> {this.state.result}
</div>
);
}
});
ReactDOM.render(
<Multiply/>,
document.getElementById('root')
);

Related

Cannot interact between react components

This is for a react JS project (jsfiddle). The textbox should update with the true/false checked value of the checkbox, but it does not do so. Can someone explain why?
var AutoGenerateCheckbox = React.createClass ({
getInitialState: function() {
return {checked: false};
},
update() {
this.state.checked = !this.state.checked;
alert(this.state.checked);
this.props.onUpdate(this.state.checked);
},
render() {
return (
<input type="checkbox" checked={this.state.checked} onChange={this.update} />
);
}
});
var TBox = React.createClass({displayName: 'TextBox',
render: function() {
return (
<div>
Checkbox value: {this.props.data}
</div>
);
}
});
var KApp = React.createClass({
getInitialState: function() {
return {autoChecked: false};
},
handleAutogenChange: function(val) {
alert('handleAutogenChange:' + val);
this.setState({autoChecked : val});
},
render: function() {
return (
<div>
<AutoGenerateCheckbox onUpdate={this.handleAutogenChange}/>
<TBox data={this.state.autoChecked}/>
</div>
);
}
});
ReactDOM.render(
<KApp />,
document.getElementById('content')
);
The reason you don't see anything printed out is because you are trying to print a boolean value here
<div>
Checkbox value: {this.props.data}
</div>
try
<div>
Checkbox value: {this.props.data.toString()}
</div>
instead.
As an extra tip, you don't really need to hold the state of the checkbox in both its own state and its parent component's state. You really only need to have it in the parent component's state.
See the fiddle I made.
React is not determining the Boolean value to be printable information, try this instead:
<div>
Checkbox value: {this.props.data.toString()}
</div>

Is this the "React.js" way of doing this?

I'm starting with React and I tried to create a simple form that says Hello name!
However I feel having 2 state elements isn't the right way to do this.
Does anyone knows or believes there's a better way to do this?
By the way, I know I can just bind the name state to the h2, but I want it to happen on click.
var Name = React.createClass({
getInitialState:function(){
return {
inputname:'',
h2name:''
};
},
showName:function(event){
event.preventDefault();
this.setState({h2name:this.state.inputname});
},
updateName:function(event){
this.setState({inputname:event.target.value});
}
,
render:function(){
return (
<div>
<form onSubmit={this.showName}>
<input onChange={this.updateName} placeholder="Enter your name"></input>
<button type="submit">Show</button>
</form>
<h2>Hello {this.state.h2name}!</h2>
</div>
);
}
});
ReactDOM.render(<Name />,document.getElementById('mount-point'));
one state is enough.
var Name = React.createClass({
getInitialState: function () {
return {
inputname: ''
};
},
showName: function (event) {
event.preventDefault();
this.setState({ inputname: this.refs.inputname.value });
},
render: function () {
return (
<div>
<input ref="inputname" placeholder="Enter your name"></input>
<button onClick={this.showName}>Show</button>
<h2>Hello {this.state.inputname}!</h2>
</div>
);
}
});
ReactDOM.render(<Name />, document.getElementById('root'));
you can use refs to get the input value.
I think you want this effect, here is the demo
here is the document of refs more-about-refs

How to get value of textbox in React?

I just started using React.js, and I'm just not sure whether there is a special way to get the value of a textbox, returned in a component like this:
var LoginUsername = React.createClass({
render: function () {
return (
<input type="text" autofocus="autofocus" onChange={this.handleChange} />
)
},
handleChange: function (evt) {
this.setState({ value: evt.target.value.substr(0, 100) });
}
});
As described in documentation You need to use controlled input. To make an input - controlled you need to specify two props on it
onChange - function that would set component state to an input value every time input is changed
value - input value from the component state (this.state.value in example)
Example:
getInitialState: function() {
return {value: 'Hello!'};
},
handleChange: function(event) {
this.setState({value: event.target.value});
},
render: function() {
return (
<input
type="text"
value={this.state.value}
onChange={this.handleChange}
/>
);
}
More specifically about textarea - here
just update your input to the value
var LoginUsername = React.createClass({
getInitialState:function(){
return {
textVal:''
}
},
render: function () {
return (
<input type="text" value={this.state.textVal} autofocus="autofocus" onChange={this.handleChange} />
)
},
handleChange: function (evt) {
this.setState({ textVal: evt.target.value.substr(0, 100) });
}
});
Your text input value is always in the state and you can get the same by this.state.textVal

React-App: Prop is updated after the next event

I've made this "Currency-Converter" to get an idea of how React works.
It works (more or less) but the result is shown with an offset:
You type "1" (Euro) => It shows "0 Dollar".
You type "10" => It shows "1.1308 Dollar".
You type "100" => It shows "11.308 Dollar".
...
var Display = React.createClass({
render: function() {
return (
<div>
<p>{this.props.euro + ' Euro are equal to ' + this.props.dollar + ' Dollar.'}</p>
</div>
)
}
});
var Converter = React.createClass({
getInitialState: function() {
return { euro: 0, dollar: 0, exchangeRate: 1.1308 }
},
convertEuroToDollar: function() {
this.setState({ euro: +document.querySelector('#amount-euro').value });
this.setState({ dollar: this.state.euro * this.state.exchangeRate });
},
render: function() {
return (
<div>
<input type="text" id="amount-euro" onKeyUp={this.convertEuroToDollar} />
<Display dollar={this.state.dollar} euro={this.state.euro} exchangeRate={this.state.exchangeRate} />
</div>
)
}
});
ReactDOM.render(
<Converter />,
document.querySelector('#app')
);
div {
margin: 30px 50px;
}
<div id="app"></div>
Live-Demo on CodePen: http://codepen.io/mizech/pen/vGbJxe
It should display the result (euro * exchangeRate) at once.
What I'm doing wrong here?
Calling two setStates one after all, you wasn't setting the euro state properly.
Being async, you was still using the old value of it.
From the docs:
setState() does not immediately mutate this.state but creates a
pending state transition. Accessing this.state after calling this
method can potentially return the existing value.
https://facebook.github.io/react/docs/component-api.html
To fix the problem, do:
convertEuroToDollar: function() {
const euro = +document.querySelector('#amount-euro').value
this.setState({
euro: euro,
dollar: euro * this.state.exchangeRate
});
},
Fixed example: http://codepen.io/FezVrasta/pen/xVeMMX
Second problem I see, it would be much better to use ref instead of document.querySelector.
convertEuroToDollar: function() {
const euro = +this.refs.amountEuro.value;
this.setState({
euro: euro,
dollar: euro * this.state.exchangeRate
});
},
render: function() {
return (
<div>
<input type="text" ref="amountEuro" onKeyUp={this.convertEuroToDollar} />
<Display dollar={this.state.dollar} euro={this.state.euro} exchangeRate={this.state.exchangeRate} />
</div>
)
}

React JS: Reusable components

I have created the form validation with a structure like this
var Signin = React.createClass({
render: function() {
return (
<Form>
<Input type="text" name="email" labelName="Email" rules="isEmail" error:"Email not valid" />
<Input type="password" name="password" labelName="Password" rules="isLength:6" error:"Passowrd not valid"/>
</Form>
);
}
});
because, for example, the "Email" input will be used in different part of application, I would avoid to add the same attributes (name, type, labelName, rules and error) every time. So I would create something like this
var InputEmail = React.createClass({
render: function () {
return (
<Input type="text" name="email" labelName="Email" rules="isEmail" error="Email not valid"/>
)
}
});
var InputPassword = React.createClass({
render: function () {
return (
<Input type="password" name="password" labelName="Password" rules="isLength:6" error="Passwordnot valid"/>
)
}
});
So the Signin Component should be
var Signin = React.createClass({
render: function() {
return (
<Form>
<InputEmail />
<InputPassword />
</Form>
);
}
});
but in this way, I get two errors:
I can't find anymore in the Form the props.name of Input because
there isn't in InputEmail;
in the render function of Input the state is null
How could I create a reausable/inherits components? I failed using both the composition pattern and the mixins
I added my full code: Form
var Form = React.createClass({
getInitialState: function () {
return {
isValid : false,
isSubmitting: false
}
},
componentWillMount: function(){
this.model = {};
this.inputs = {};
this.registerInputs(this.props.children);
},
registerInputs: function(children){
React.Children.forEach(children, function (child) {
if (child.props.name) {
child.props.attachToForm = this.attachToForm;
child.props.detachFromForm = this.detachFromForm;
child.props.validate = this.validate;
}
if (child.props.children) {
this.registerInputs(child.props.children);
}
}.bind(this));
},
attachToForm: function (component) {
this.inputs[component.props.name] = component;
this.model[component.props.name] = component.state.value;
this.validate(component);
},
detachFromForm: function (component) {
delete this.inputs[component.props.name];
delete this.model[component.props.name];
},
validate: function (component) {
var isValid = true;
// validation code
component.setState({
isValid: isValid,
}, this.validateForm);
},
validateForm: function () {
var formIsValid = true;
var inputs = this.inputs;
Object.keys(inputs).forEach(function (name) {
if (!inputs[name].state.isValid) {
formIsValid = false;
}
});
this.setState({
isValid: formIsValid
});
},
updateModel: function (component) {
Object.keys(this.inputs).forEach(function (name) {
this.model[name] = this.inputs[name].state.value;
}.bind(this));
},
submit: function (event) {
event.preventDefault();
this.setState({
isSubmitting : true
});
this.updateModel();
console.log(this.model);
},
render: function () {
return (
<form className="ui form" onSubmit={this.submit}>
{this.props.children}
<button className="ui button" type="submit" disabled={this.state.isSubmitting}>Accedi</button>
</form>
);
}
});
Input
var Input = React.createClass({
getInitialState: function(){
return {
value : this.props.value || "",
isValid: true
}
},
setValue: function (event) {
this.setState({
value: event.target.value
}, function () {
this.props.validate(this);
}.bind(this));
},
componentWillMount: function () {
if (this.props.required) {
this.props.validations = this.props.validations ? this.props.validations + ',' : '';
this.props.validations += 'isLength:1';
}
// ERROR: TypeError: this.props.attachToForm is not a function
this.props.attachToForm(this);
},
componentWillUnmount: function () {
this.props.detachFromForm(this);
},
render: function () {
var className = "field";
if(this.props.className){
className += " " + this.props.className;
}
if(this.props.required){
className += " required";
}
var Label;
if(this.props.labelName){
Label = (<label htmlFor={this.props.name}>{this.props.labelName}</label>);
}
var Error;
if(!this.state.isValid){
Error = (<div className="ui">{this.props.error || this.props.name + " not valid"}</div>);
};
return (
<div className={className}>
{Label}
<input type={this.props.type || "text"} id={this.props.name} name={this.props.name} onChange={this.setValue} value={this.state.value} />
{Error}
</div>
);
}
});
With this works
ReactDOM.render(
<Form>
<Input type="text" name="email" labelName="Email" rules="isEmail" error:"Email not valid"/>
</Form>,
document.getElementById('app')
);
In this way I get:
"TypeError: this.props.attachToForm is not a function
this.props.attachToForm(this);"
ReactDOM.render(
<Form>
<InputEmail/>
</Form>,
document.getElementById('app')
);
P.S: I tried to add this code on jsfiddle but I get "!TypeError: can't define property "attachToForm": Object is not extensible"
jsfiddle
There are 2 main issues with your setup:
Your <Form> is set up in such a way, that the children of the form need to have props, otherwise it does not work.
The <InputEmail> wrapper is incomplete. It needs to pass along all props to the <Input>, including the Form functions passed down.
Ad 1: Fix the form, to ensure validation methods are added
The reason you get the error is because the children of your <Form> need to have props.name. It then registers the functions of the form (including attachToForm), by adding them to the children. This is done in the method registerInputs().
In the original variant, the <Input> component has props, so all goes well.
In the adapted variant, the wrapper <InputEmail> no longer has props, so the attachToForm() and other functions are not added to props, and you get the error when the <Input> tries to invoke the function.
Simplest way to fix this: add at least 1 prop in the render function, and check this in the registerInputs(), e.g.:
ReactDOM.render(
<Form>
<InputEmail initialValue={'name#domain.com'}/>
</Form>,
document.getElementById('app')
);
And in registerInputs(), change the line:
if (child.props.name) {
to:
if (child.props.initialValue) {
2. Extend <InputEmail> wrapper to pass down functions as well
Simplest way to do this is to add {...this.props}, like this:
var InputEmail = React.createClass({
render: function () {
return (
<Input {...this.props}
type="text" name="email" labelName="Email" rules="isEmail" error="Email not valid"/>
)
}
});
That way, the functions passed down by <Form> to the <InputEmail> component (as well as any other props), will be passed down to the <Input> component.
PS: The code inside registerInputs() that checks for child.props.children does not work as intended: at the time it is invoked, the <InputEmail> component does not have children. Like the name implies, it checks for children passed down as props. And the only prop passed was initialValue.
As minor issues I would suggest to make 2 more changes:
In registerInputs(), you directly modify props. This is generally not a good idea. Better is to make a copy of props, and add your form-methods to the copy. You can use React.Children.map to do this. See official docs here.
Instead of hard-coding the name="email" etc of your <Input> component, inside <InputEmail>, better is to put the default values of these in default values of props, using propTypes, as explained here in official docs.

Categories

Resources