Why does the value in event.target not equal event.target.value - javascript

I am learning react, and noticed when changing an input of type number and outputting event.target I see a different value then that when I output event.target.value.
I am wondering why this is?
Some sample code to show what I am talking about:
class Child extends React.Component {
render() {
return (
<input type="number"
value={this.props.weight}
onChange={(event) => this.props.onWeightChange(event, this.props.index)}
step="0.1" />
);
}
}
class Parent extends React.Component {
state = {
text: 'Goals',
weight: 1
}
handleStatWeightChange = (event, index) => {
console.log(event.target)
console.log(event.target.value)
}
render() {
return (
<div>
<Child weight={this.state.weight} onWeightChange={this.handleStatWeightChange}/>
</div>
);
}
}
React.render(<Parent />, document.getElementById('app'));
When changing the input value (from 1.1 from 1) I see the following output in the console:
"<input type='number' value='1' step='0.1' data-reactid='.0.0'>"
"1.1"
why is the value in event.target still 1?

You are not setting event.target.value to weight in handleStatWeightChange event handler function
Try with below change it would work
handleStatWeightChange = (event, index) => {
this.setState({
weight: event.target.value
})
console.log(event.target)
console.log(event.target.value)
}

Related

Modfying state in React using Onclick

im very new to React, just wanted to make a simple program that has multiple buttons that correspond to some value in state, what i want is when a button is pressed, the respective value negates
class Parent extends React.Component{
constructor(props){
super(props);
this.state={
a: true,
b: false,
c: true,
d: false
}
this.handleAction = this.handleAction.bind(this);
}
handleAction(action) {
this.setState({
name: !this.state.name
});
}
render(){
return(
<div>
<Child onAction={this.handleAction} name='a'/>
<Child onAction={this.handleAction} name='b'/>
<Child onAction={this.handleAction} name='c'/>
<Child onAction={this.handleAction} name='d'/>
</div>
)
}
}
function Child({onAction, name}){
return (
<button onClick={onAction}>
{name}
</button>
);
}
is there a way to do this without 4 separate handleAction functions ? i tried passing name to onAction but that throws Error: Maximum update depth exceeded
i know there must be something really obvious that i'm missing, thank you for your help.
You could pass the name as a parameter to your handleAction function
....
handleAction(name) {
this.setState( state => ({ [name]: !state[name] }) );
}
render(){
return(
<div>
<Child onAction={() => this.handleAction('a')} name='a'/>
<Child onAction={() => this.handleAction('b')} name='b'/>
<Child onAction={() => this.handleAction('c')} name='c'/>
<Child onAction={() => this.handleAction('d')} name='d'/>
</div>
)
}
...
Note that reading from this.state inside this.setState isn't good practice. see here
Change the handler so that it can accept name and return another function.
handleAction(name) {
return () => {
this.setState({
[name]: !this.state[name],
});
};
}
In child component pass the name of that child
<Child onAction={this.handleAction("a")} name='a'/>
Try this out:
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
a: true,
b: false,
c: true,
d: false,
};
this.handleAction = this.handleAction.bind(this);
}
handleAction(name) {
return () => {
console.log("name", name);
this.setState({
[name]: !this.state[name],
});
};
}
render() {
console.log("this.state", this.state);
return (
<div>
<Child onAction={this.handleAction} name="a" />
<Child onAction={this.handleAction} name="b" />
<Child onAction={this.handleAction} name="c" />
<Child onAction={this.handleAction} name="d" />
</div>
);
}
}
function Child({ onAction, name }) {
return <button onClick={onAction(name)}>{name}</button>;
}
As I see you want to use the name of the button and then to change the state with the same name. First, you should provide the name of the button to the function. As the event is passed to the function by default, you can get the name for example like this:
event.target.innerText
Then, if you use the name as variable containing the value you must use [name] notation. Otherwise, it will add the 'name' property to your object.
As the result your handler should look like this:
handleAction(e) {
const name = e.target.innerText
this.setState({
[name]: !this.state[name]
});
}

How to invoke child component function from parent component?

I have an input field component that meets these conditions:
Upon first focus, nothing happens until the field is valid, then a valid class is applied
Upon first blur, if the field is invalid, apply an invalid class.
After the first blur, upon any further engagement with the field, a class is applied whenever the value of the field changes from valid to invalid or vice versa.
To achieve this I have done this:
import React, { Component } from "react";
class Input extends Component {
constructor(props) {
super(props);
this.state = {
touched: false,
valid: false,
focused: false,
value: ""
};
this.handleFocus = this.handleFocus.bind(this);
this.handleBlur = this.handleBlur.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleFocus() {}
handleBlur() {
if (!this.state.touched) {
this.setState({
touched: true
});
} else if (this.state.touched) {
this.setState({
focused: true
});
}
}
handleChange(e) {
const val = e.target.value
this.setState({ value: val }, () => {
this.validateField();
}
);
}
validateField() {
const touched = this.state.touched;
const focused = this.state.focused;
const valid = this.state.valid;
const value = this.state.value;
if (value.length >= 5) {
this.setState({
valid: true,
touched: true
});
} else {
this.setState({ valid: false });
}
}
render() {
return (
<div>
<input
id={this.props.id}
name={this.props.name}
type="text"
className={`form-control ${styles["kyi-input"]} ${
this.state.valid ? "is-valid" : ""
} ${this.state.touched && !this.state.valid ? "is-invalid" : ""}`}
required
spellCheck="false"
autoComplete="off"
onFocus={this.handleFocus}
onChange={this.handleChange}
value={this.state.value}
onBlur={this.handleBlur}
placeholder={this.props.placeholder}
/>
</div>
);
}
}
class Parent extends Component {
handleInput(val, name) {
// Can get value of input here
this.setState({
[name]: val
});
}
render() {
<Input placeholder="Test" onChange={(val) => {this.handleInput(val, 'inputName')}}/>
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
It works, but this means that the state of the field lives in the child component and not the parent.
The input field's onBlur function is reliant on the state of the field.
Is there a way to refactor this so that the input state lives in the parent component while the onBlur function lives in the child component?
I think you should get all your State in the Parent component, you should also get all the functions that modify it in the Parent Component. This would allow you to have a 'single source of truth' that keeps track of state's changes and pass it to all your child components.
Check out Lifting state up

How can i clear my input when i'm submit my event (reactJs app)

I have 3 inputs whose value I save and click on my btn, I would like to clear these inputs.......
my function that saves the value of one of my inputs:
onChangeIdentity = (event) => {
this.newPlayer = Object.assign({}, this.newPlayer, { strPlayer:
event.target.value})
}
my input:
<Input style={{width:'30%'}} onChange={ this.onChangeIdentity }
ref='myFormRef' value={ this.newPlayer.strPlayer } type='text'
placeholder='Nom & Prenom'/>
and the function that must clear my input:
addPlayer = () => {
console.log('my new Player: ' , this.newPlayer);
this.setState({
teamPlayers: [...this.state.teamPlayers, this.newPlayer]
})
this.refs.myFormRef.value = ""
}
I tried several ways to declare my refs but nothing works.....
any ideas?
You input's values are driven by the state of the component value={this.newPlayer.strPlayer}. If you want to clear the input's value you need to clear the state which maps to it, for example:
this.setState({newPlayer: {strPlayer: ''}});
After setting the state, the component updates automatically and renders the input as empty.
Here is a full example component:
class MyComponent extends Component {
state = {
inputValue: ""
};
render() {
return (
<div>
<input
type="text"
value={this.state.inputValue}
onChange={event => this.setState({ inputValue: event.target.value })}
/>
<button
onClick={() => {
/* submit this.state.inputValue */
this.setState({ inputValue: "" }); // reset input value
}}
>
submit
</button>
</div>
);
}
}

How to add values of dyanamically added fields

I've tried to add new fields here, each time button '+' is clicked it adds field input. It is working fine but the problem I've stuck upon is I want to add the value of those input fields. As I am new to react I am not finding a way to achieve it. Is it possible to achieve this.
class InputFields extends React.Component{
render(){
return (
<div>
<input name={`value[${this.props.index + 1}]`} onChange={this.onChangeValue} />
</div>
);
}
}
class Main extends React.Component{
constructor(props){
super(props);
this.values = props.value;
this.state={
inputs:[],
values:[]
};
this.addInputs = this.addInputs.bind(this);
}
addInputs() {
const inputs = this.state.inputs.concat(InputFields);
this.setState({ inputs });
}
onChangeValue(e){
var value = e.target.value;
this.value =value;
this.addValues();
}
addValues(){
...
}
render () {
const inputs = this.state.inputs.map((Element, index) => {
return <Element key={ index } index={ index } />
});
return <div>
<div>
<input name={`value[${this.props.index}]`} onChange={this.onChangeValue} />
</div>
<div>
<button className="btn btn-sm btn-primary" onClick={this.addInputs}>+</button>
</div>
</div>
}
}
ReactDOM.render(
<Main />,
document.getElementById('calculator')
);
It't not required to manage two different variables to manage it, you can loop it through the array and can change the value on onChange event
import React from "react";
export default class Example extends React.Component {
state = {
values: [null]
};
add() {
this.setState(prevState => prevState.values.push(null));
}
changeVal(val, index) {
this.setState(prevState => (prevState.values[index] = parseFloat(val)));
}
getSum() {
let sum = 0;
for (let i = 0; i < this.state.values.length; i++) {
if (this.state.values[i] !== null) {
sum += this.state.values[i];
}
}
return sum;
}
render() {
return (
<div>
{this.state.values.map((val, index) => (
<div key={index}>
<input
onChange={e => this.changeVal(e.target.value, index)}
type="number"
value={val}
placeholder="Enter a value"
/>
</div>
))}
<hr />
Sum is {this.getSum()}
<hr />
<button onClick={this.add.bind(this)}> +Add</button>
</div>
);
}
}
Edit
Added the method getSum() and converting the number to float in changeVal() method
Codesandbox link - https://codesandbox.io/s/235o6xoxyr
In react, the view is a function of data: UI = fn(data)
This means that you'll write a component tree that can transform data to view.
And only manipulate data, unlike what you might be familiar with in jQuery for example.
In practice, this would mean:
let a component Input handle the rendering of one input:
const Input = ({value, onChange}) =>
<input value={value} onChange={event => event.target.value} />
in your state, only save the list of input values as strings. React will take care of transforming each value to an Input component later on
this.state = {inputs: []}
write a function responsible of adding new inputs, to the state and not the view
addInput = () => {
this.setState({
inputs: this.state.inputs.concat('')
})
}
create a method that takes care of changing the value of one input in the list
changeValue = (i, newValue) => {
this.setState({
inputs: [
...this.state.inputs.slice(0, i),
newValue,
...this.state.inputs.slice(i+1)]
})
}
in the render method of Main, loop over your list of inputs and transform to a list of Input components
this.state.inputs.map(
(input, i) =>
<Input
key={i}
value={input}
onChange={newValue => this.changeValue(i, newValue)}
/>
)

Create price range fields (min and max) using reactJS

after spending a lot time I need help here.
I am creating a template. Where I can use different form fields. Everything is working. I am getting value form all fields as expected.
But problem is when I have 2 input fields together in one component and pass this component to parent component and get the value. then save this value in object.
I hope its clear enough. Thank you in advance
class Parent extends Component {
handlePriceMinMax(event) {
console.log(event.target.value);
/* I cant set the right values here.
* These values get overwritten with latest value.
* Because I get value on keypress/onChange value */
this.setState({
priceRange: {
min: event.target.value,
max: event.target.value
}
}
);
}
render() {
return (
<Child onChange={this.handlePriceMinMax}/>
)
}
}
class Child extends Component {
render() {
return (
<div className="form-group">
<label>Price</label>
<input type="number" onChange={this.props.onChange}/>
<input type="number" onChange={this.props.onChange}/>
</div>
);
}
}
export default Child;
https://codesandbox.io/s/zr30923nrm
I think this should work.
So basically you need to tell to the handlePriceMinMax what value do you want to update.
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = { priceRange: { min: 0, max: 0 } };
}
handlePriceMinMax = (value, event) => {
const priceRange = this.state.priceRange;
priceRange[value] = event.target.value;
this.setState({ priceRange });
};
render() {
return <Child onChange={this.handlePriceMinMax} />;
}
}
class Child extends React.Component {
render() {
return (
<div className="form-group">
<label>Price</label>
<input type="number" onChange={this.minChange} />
<input type="number" onChange={this.maxChange} />
</div>
);
}
minChange = e => {
this.props.onChange("min", e);
};
maxChange = e => {
this.props.onChange("max", e);
};
}
I changed my code, you can create function in child first that get target value and pass to props function
class Child extends Component {
submitInput(e) {
this.props.onChange(e)
}
render() {
return (
<div className="form-group">
<label>Price</label>
<input type="number" onChange={(e) => this.submitInput(e)}/>
<input type="number" onChange={(e) => this.submitInput(e)}/>
</div>
);
}
}
export default Child;

Categories

Resources