Input elements not updating in React - javascript

I am building a very basic React application but having some issues with form inputs:
My state:
class App extends Component {
constructor(){
super();
this.state = {
books: [],
book:{
author:"",
title: ""
}
}
this.handleInputChange = this.handleInputChange.bind(this)
}
My form:
<form onSubmit={this.addBook}>
<input
name="author"
type="text"
placeholder="author"
value={this.state.book.author}
onChange={this.handleInputChange}
/><br/>
<input
name="title"
type="text"
placeholder="title"
value={this.state.book.title}
onChange={this.handleInputChange}
/><br/>
<input type="submit" />
<button>Update</button>
<button>Delete</button>
</form>
My event handler:
handleInputChange(event) {
this.setState({
[event.target.name]: event.target.value
});
}
Still I am not able to digit in the input field. When I try to digit a value nothing happens and the input field is not updating properly. Any suggestions?
Thanks

Your book state is state.book.title and state.book.author, so you need to specify in setState that it's the state.book object that you want to update with the event.target.value.
Hopefully this will do the trick:
handleInputChange(event) {
this.setState({
book: {
...this.state.book,
[event.target.name]: event.target.value
},
});
}
When updating state for your nested book object, you need to make a copy of it, but with the property you want changed set to the new value. This is what the ellipsis notation helps with.
More info here: How do I setState for nested array?

The title/author properties are within the book object. It looks like you're only referencing state.author or state.title, but you need to reference state.book.title or state.book.author. Try this:
handleInputChange(event) {
this.setState({
book[event.target.name]: event.target.value
});
}

Related

ReactJS OnKeyUp event not getting value on controlled input

I'm building a ReactJS search component for data filtering through search.
The idea is that the user types a word, letter after letter, and the system will filter all registers containing that word. The basic component is detailed below:
class SearchInput extends Component {
static propTypes = {
onKeyUp: PropTypes.func,
placeHolder: PropTypes.string,
value: PropTypes.string
};
state = {
searchText: ""
};
handleKeyUp = event => {
console.log(event.target.value) // <== No result. Always empty
let newSearchText = event.target.value;
this.setState({ searchText: newSearchText });
if (this.props.onKeyUp) this.props.onKeyUp(newSearchText);
};
render() {
console.log(this.state.searchText) // <== Always empty
return (
<div className="search-input">
<div className="search-input-icon">
<Icon name="faSearch" />
</div>
<input
autoFocus="true"
type="text"
onKeyUp={this.handleKeyUp}
placeholder={this.props.placeHolder}
value={this.state.searchText}
/>
</div>
);
}
I'm not getting the key pressed value on the handleKeyUp event handler.
It works if I ommit the value={this.state.searchText} (uncontrolled) from the code, but I need a way to set the searchText from outside the component (initialization, other component selection, etc.).
Why am I not getting the event.target.value data on my handler? How to fix it?
I'm pretty sure you have to listen to the onChange event on an input field to get the updated target value. simply change
<input onKeyUp={this.handleKeyUp} />
to
<input onChange={this.handleKeyUp} />
Try to use event.key instead.
The event.target.value just points to your this.state.searchText which hasn't been set yet.
seems you forgot to bind the function on the constructor:
class SearchInput extends Component {
constructor(props) {
super(props);
this.handleKeyUp = this.handleKeyUp.bind(this);
}
//... any code here
handleKeyUp = event => {
console.log(event.target.value);
}
render() {
//... any code here
<input
autoFocus="true"
type="text"
onKeyUp={this.handleKeyUp}
placeholder={this.props.placeHolder}
value={this.state.searchText}
/>
}
}
Use this:
let newSearchText = event.target.getAttribute('value')

Updating 'state' dynamically in React overwrites entire state

Ok, so I'm trying to build a form in React where I can enter values in multiple inputs, then submit and have the values populate designated cells in a table. I'm trying to get the state to update using 'onChange', but when I enter the values, my initial state gets overwritten entirely.
So, if I set:
state = {
Jan012019: {
first: null,
second: null
}
};
then try to update state by entering '3' into the input for 'first' using:
this.setState(
{
Jan012019: {
[e.target.name]: e.target.value
}
},
function() {
console.log(this.state);
}
);
state displays as:
Jan012019 {
first: '3'
}
completely removing 'second' from state, and if I try to then also enter values into the 'second' input, it removes 'first' from the state. What's going on here? I've seen other examples and solutions, and I'm fairly certain my code was exactly like a solution from another question on here, but still won't work correctly. Full code below.
import React from "react";
class InputForm extends React.Component {
state = {
Jan012019: {
first: null,
second: null
}
};
updateTable = e => {
this.setState(
{
Jan012019: {
[e.target.name]: e.target.value
}
},
function() {
console.log(this.state);
}
);
};
onClick = e => {
e.preventDefault();
console.log(this.state);
};
render() {
return (
<form className="ui form" style={{ marginTop: "50px" }}>
<div className="inline field">
<label style={{ marginRight: "27px" }}>First Input</label>
<input
name="first"
type="number"
placeholder="Enter value"
onChange={this.updateTable}
/>
</div>
<div className="inline field">
<label>Second Input</label>
<input
name="second"
type="number"
placeholder="Enter value"
onChange={this.updateTable}
/>
</div>
<button onClick={this.onClick}>Click</button>
</form>
);
}
}
export default InputForm;
I also tried setting the input values to:
value={this.state.Jan012019.first}
to see if that made any difference, but no go.
That is because you are resetting the whole Jan012019 object in your setState.
Jan012019: {
[e.target.name]: e.target.value
}
You need to spread the original Jan012019 object first, to preserve the other fields
this.setState({
Jan012019: {
...this.state.Jan012019, [e.target.name]: e.target.value
}
})

react js multiple input form

Am trying to build form inputs in reactjs. the code below works for just one form inputs.
Now I want to add two more form inputs as per
Firstname <input type="text" id="fname" name="fname"><br>
Lastname <input type="text" id="lname" name="lname"><br>
below is the working code that I want to implement the two form inputs above.
source
https://reactjs.org/docs/forms.html
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
The best way I've found to manage forms in React is to make sure each of your <input> tags has a name value. Then ensure that your component's state has fields for each input that matches the name exactly.
In your onChange handler, you can then say:
handleChange(event) {
this.setState({ [event.target.name]: event.target.value });
}
This will update the state with change to any of the inputs, and apply the change to that specific state value.
Then for handleSubmit, you send those values from state to where ever you need to process the form information.
try this one
handleChange(event){
this.setState({[event.target.name]:event.target.value});
this.setState({[event.target.name]:event.target.value});
}

Why my onChange do not work when state have object on ReactJs

I tried to build a app use ReactJS by ES6
class MyApp extends React.Component{
constructor(props){
super(props);
this.state = {
employee:{
name: 'hello',
birthday: ''
},
price: ''
}
this.handleValueChange = this.handleValueChange.bind(this);
}
handleValueChange(event){
valueName = event.target.name
this.setState({[valueName]: event.target.value});
};
render(){
return(
<form>
<input type="text" placeholder="name" value={this.state.employee.name} onChange={this.handleValueChange} name="name"/>
<input type="text" placeholder="name" value={this.state.price} onChange={this.handleValueChange} name="price"/>
</form>
)
}
}
As my Code, I used handleVauleChange in onChange event to change the default state of the input html tag.If the data in this.state is object(like employee), the handleVauleChange function will not work, but the data is like price, it will work fine.
Why has it happened?
Your setState for the name input should be like this...
this.setState({
employee: {
[valueName]: event.target.value
}
});
Not sure how dynamic the state structure you need but for one level deep structure, you can do something like this...
handleValueChange(event) {
const valueName = event.target.name;
const parent = valueName.indexOf('.') !== -1 ? valueName.split('.')[0] : false;
if (parent) {
this.setState({
[parent]: {
[valueName]: event.target.value
}
});
} else {
this.setState({
[valueName]: event.target.value
});
}
}
and on your input fields...
<input
type="text"
placeholder="name"
name="employee.name"
value={this.state.employee.name}
onChange={this.handleValueChange} />
<input
type="text"
placeholder="price"
name="price"
value={this.state.price}
onChange={this.handleValueChange} />
created jsbin:
http://jsbin.com/vopixexixe/edit?js,console,output#J:L14
In name input your setting input value from this.state.employee.name which is "hello" but on change your setting changed value to this.state.name
but in case of price your setting input value from this.state.price and updating to this.state.price, so value is reflecting.
In case of "name" you edit state.name and you want to edit state.employee.name I think

How to avoid duplicate event listener in react?

I have a form in react with many input components. I do not like that I have to write a new onChange handler method for every input component that I build. So I want to know how can I stop repeated code.
<Input
label={"Blog Name"}
hint={"e.g. 'The Blog'"}
type={"text"}
value={this.state.name}
onChange={this.handleInputChange.bind(this, "name")}
/>
<Input
label={"Blog Description"}
hint={"e.g. 'The Blog Description'"}
type={"text"}
value={this.state.desc}
onChange={this.handleInputChange.bind(this, "desc")}
/>
So instead of writing a new function I am reusing the same function and passing an extra value. Is this the right way to do it? How do other experienced people solve this problem.
If you want your parent component to maintain the state with the value of each input field present in 'Input' child components, then you can achieve this with a single change handler in the following way:
handleChange(id, value) {
this.setState({
[id]: value
});
}
where the id and value are obtained from the Input component.
Here is a demo: http://codepen.io/PiotrBerebecki/pen/rrJXjK and the full code:
class App extends React.Component {
constructor() {
super();
this.state = {
input1: null,
input2: null
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(id, value) {
this.setState({
[id]: value
});
}
render() {
return (
<div>
<Input id="input1"
changeHandler={this.handleChange} />
<Input id="input2"
changeHandler={this.handleChange} />
<p>See input1 in parent: {this.state.input1}</p>
<p>See input2 in parent: {this.state.input2}</p>
</div>
);
}
}
class Input extends React.Component {
constructor() {
super();
this.state = {
userInput: null
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
const enteredText = event.target.valuel
this.setState({
userInput: enteredText
}, this.props.changeHandler(this.props.id, enteredText));
}
render() {
return (
<input type="text"
placeholder="input1 here..."
value={this.state.userInput}
onChange={this.handleChange} />
);
}
}
ReactDOM.render(<App />, document.getElementById('app'));
You can try event delegation, just like the traditional ways.
That is, just bind a function to the parent form element, and listens to all the events bubbling up from the children input elments.

Categories