I've made a form in ReactJS with one text input and when it submits I want to get its value and put it into a variable. But when I console.log() it returns as undefined. How do I fix this? Here is my code.
class App extends Component {
state = {
todoTitle: ""
};
render() {
return (
<div>
<center>
<form
onSubmit={(event) => {
event.preventDefault();
this.setState(todoTitle: event.target.value,);
console.log(this.state.todoTitle); // Returns "undefined"
}}
>
<input
type="text"
autocomplete="off"
class="form-control"
name="todoInput"
placeholder="Enter todo"
style={{ width: "400px", height: "50px" }}
/>
<input
type="submit"
value="Submit"
id="submitButton"
></input>
</form>
</center>
}
}
}
You need to either make a controlled input or useRef for un-controlled input for the React to keep track of your todoTitle state.
To make a controlled input, you will need to use onChange event and a value={this.state.todoTitle} property.
Also on your form, it is best to add an onSubmit event. There is however an option to set the submit on the form submit button also. In that case we need to use onClick={this.handleSubmit} as follows <input type="submit" value="Submit" id="submitButton" onClick={this.handleSubmit} />.
The below code will work for you:
class Form extends React.Component {
state = {
todoTitle: "",
};
handleSubmit = (e) => {
e.preventDefault();
console.log(this.state.todoTitle);
};
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<input
type="text"
autocomplete="off"
class="form-control"
name="todoInput"
placeholder="Enter todo"
style={{ width: "400px", height: "50px" }}
value={this.state.todoTitle}
onChange={(e) => this.setState({ todoTitle: e.target.value })}
/>
<input type="submit" value="Submit" id="submitButton" />
</form>
</div>
);
}
}
You can modify your app a bit to get the value on onChange of input textfield, and then store it in the array in case of below example:
export default class App extends React.Component {
state = {
todoTitle: "",
todoList: []
};
render() {
return (
<div>
<center>
<form
onSubmit={event => {
event.preventDefault();
this.setState(
{
todoList: [...this.state.todoList, this.state.todoTitle]
},
() => {
console.log(this.state.todoList);
}
);
}}
>
<input
type="text"
autocomplete="off"
class="form-control"
name="todoInput"
placeholder="Enter todo"
onChange={event => {
this.setState({ todoTitle: event.target.value });
console.log(event.target.value);
}}
style={{ width: "400px", height: "50px" }}
/>
<input type="submit" value="Submit" id="submitButton" />
</form>
</center>
</div>
);
}
}
Full app here: Stackblitz
There are a few other errors with your code, but I will just answer your question.
setState triggers a re-render, so your state isn't available to log until the next time it runs. You can just log what you put in setState.
console.log(event.target.value);
This question has more info.
setState doesn't update the state immediately
Also, you can do a callback.
this.setState({ todoTitle: event.target.value }, () =>
console.log(this.state.todoTitle)
);
Try this:
class App extends React.Component {
constructor(props) {
super(props);
this.state = { todoTitle: "" };
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
event.preventDefault();
this.setState({ todoTitle: event.target.value });
}
handleSubmit(event) {
event.preventDefault();
console.log(this.state.todoTitle);
}
render() {
return (
<div>
<center>
<form onSubmit={this.handleSubmit}>
<input
type="text"
autocomplete="off"
class="form-control"
name="todoInput"
placeholder="Enter todo"
style={{ width: "400px", height: "50px" }}
onChange={this.handleChange}
/>
<input type="submit" value="Submit" id="submitButton" />
</form>
</center>
</div>
);
}
}
This will change the state on input changes and then logs on submit the state. An alternative would be to just get the input element and its value via getElementById or something similar in React.
Your code was also not very well formatted and a lot of closing tags missed.
Read more here:
Get form data in ReactJS
Related
I've tried using onSubmit on both the inputs and the submit button but I know that's wrong. and I've tried connecting the functions to the inputs. I've seen examples of people using https links to get it posted but I just want to be able to change the color and text when you click submit.
this.state = {
deftextcolor: "green",
text: "Color Me"
}
}
colorchanger(newcolor) {
this.setState({deftextcolor: newcolor})
}
textchanger(newtext) {
this.setState({text: newtext})
}
render() {
return (
<div className='colorer-wrapper'>
<h1 style={{color: this.state.deftextcolor}}>{this.state.text}</h1>
<input type="text"/>
<input type="text"/>
<button type="submit">Submit</button>
</div>
);
}
}
here some example:
const App =()=>{
const [state,setState] = React.useState({bgColor:"",textColor:"",color:"white",backgroundColor:"red"});
const handleChange = (e)=>{
const {target} = e
setState(current =>({...current,[target.name]:target.value}))
}
const onSubmit = (e)=>{
e.preventDefault();
if(state.bgColor.length>0 && state.textColor.length>0)
setState((current)=>({bgColor:"",textColor:"",color:current.textColor,backgroundColor:current.bgColor}))
}
return (<div><form style={{backgroundColor:state.backgroundColor,color:state.color}} onSubmit={onSubmit}>
<div>test style color</div>
<input type="text" name="bgColor" placeholder="background color" value={state.bgColor} onChange={handleChange}/>
<input type="text" name="textColor" value={state.textColor} onChange={handleChange} placeholder="text color"/>
<button type="submit">Apply style </button>
</form></div>)
}
ReactDOM.render(<App/>,document.getElementById("root"))
form{
width:100vw;
height:100vh
}
<script src="https://unpkg.com/react#16/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js" crossorigin></script>
<div id="root"></div>
remenber you need to store event in variable because react update state asynchronously so the event will be gone.
Two places you can wire with onSubmit,
wire it with a button directly
<button onClick={onSubmit} />
wire it with form
<form onSubmit={onSubmit}>
<button type="submit" />
</form>
Your function needs to look like
const onSubmit = (e) => {
// do something. here
}
In your case, you also want to pass something into this function, so either calling handleSubmit directly or <button onClick={ e=> { colorchanger(color) } />
Like this:
import React from 'react';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
deftextcolor: "green",
text: "Color Me",
defInput: '',
textInput: ''
}
}
handleChange = (e) => {
this.setState({[e.target.id]: e.target.value})
}
handleSubmit = () => {
this.setState((state) => ({
deftextcolor: state.defInput,
text: state.textInput,
defInput: '',
textInput: ''
}))
}
render() {
return (
<div className='colorer-wrapper'>
<h1 style={{color: this.state.deftextcolor}}>{this.state.text}</h1>
<input type="text" value={this.state.defInput} onChange={this.handleChange} id="defInput"/>
<input type="text" value={this.state.textInput} onChange={this.handleChange} id="textInput"/>
<button type="submit" onClick={this.handleSubmit}>Submit</button>
</div>
);
}
}
export default App
You can attach the same method to both inputs to update state input values, and then another method to the button that uses state input values to update your other state properties.
I have three inputs, and I want each input's data to be stored in a state. For example, the name input should be stored in the name state, because I'll need it later to push the three states' values in a firebase database.
I used the onChange function to store the data, but I didn't know how to make each input's function relative to the state I want to put it in.
import React from "react";
import ReactDOM from "react-dom";
export default class Inputs extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "",
email: "",
age: ""
};
}
handleChange = e => {
this.setState({ name: e.target.value });
};
render() {
return (
<div>
<form>
<label>
name:
<input type="text" name="name" onChange={this.handleChange} />
</label>
<label>
email:
<input type="text" name="email" onChange={this.handleChange} />
</label>
<label>
age:
<input type="text" name="age" onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
<textarea value={this.state.value} onChange={this.handleChange} />
<button onClick={() => this.props.onClick(this.state.value)}>
Add task
</button>
</div>
);
}
}
getChanges = (e) => {
console.log(e);
this.setState({[e.target.name]: e.target.value}, function () {
console.log(this.state)
})
};
call this function,
<Input onChange={(e) => this.getChanges(e)} name={'name'}
value={this.state.name} placeholder={'Name'}/>
You can pass key and value
<input type="text" name="name" onChange={(event)=>this.handleChange(event,'name')} />
and in your function you can do something like this
handleChange = (e,key) => {
this.setState({ [key] : e.target.value });
};
I'm using Formik (with withFormik()) and want to check a <Field> as a user types in it - after it has 4 characters in it, I want to focus on the next field so they can keep typing without having to move to the next field.
So my InnerForm has:
<Field
type="text"
name="credit1"
inputmode="numeric"
maxlength="4" />
<Field
type="text"
name="credit2"
inputmode="numeric"
maxlength="4" />
And my FormikInnerFormContainer = withFormik(...) has a validationSchema.
How could I catch changes on the first field, and move focus to the 2nd field if the first has 4 characters in?
I tried to override the onChange, but couldn't figure out how to update the Field contents with each character the user types.
You might use like this in Formik.
focusChange(e) {
if (e.target.value.length >= e.target.getAttribute("maxlength")) {
e.target.nextElementSibling.focus();
}
...
//Example implementation
import React from "react";
import { Formik } from "formik";
export default class Basic extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
this.focusChange = this.focusChange.bind(this);
}
focusChange(e) {
if (e.target.value.length >= e.target.getAttribute("maxlength")) {
e.target.nextElementSibling.focus();
}
}
render() {
return (
<div>
<h1>My Form</h1>
<Formik
initialValues={{ name: "" }}
onSubmit={(values, actions) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
actions.setSubmitting(false);
}, 1000);
}}
render={props => (
<form onSubmit={props.handleSubmit} ref={this.inputRef}>
<input
type="text"
onChange={props.handleChange}
onBlur={props.handleBlur}
value={props.values.name}
name="name"
maxlength="4"
onInput={e => this.focusChange(e)}
/>
<input
type="text"
onChange={props.handleChange}
onBlur={props.handleBlur}
value={props.values.lastName}
name="lastName"
maxlength="4"
onInput={this.focusChange}
/>
<button type="submit">Submit</button>
</form>
)}
/>
</div>
);
}
}
In vanilla javascript you can do this:
document.querySelectorAll('input').forEach(function(input) {
input.addEventListener('keyup', function() {
if(input.value.length >= input.getAttribute('maxlength'))
input.nextElementSibling.focus();
});
})
In my component, I'm trying to call in an handleChange and handleSubmit functions of a component
If I render like the forms example,
<form onSubmit={this.handleSubmit}>
<input type="text" value={this.state.value} onChange={this.handleChange} placeholder="Enter new title"/>
<input type="submit" value="Submit" />
</form>
in onChange(), this won't be bound to the component, and I can't call this.setState, so I bind it with onChange={() => this.handleChange}.
for onSubmit(), I have the same binding problem, but when I bind it, the handler is not called, and the page is reloaded. What is the right way to bind to the component when submitting?
TIA
Full example:
class CbList extends React.Component {
constructor() {
super();
this.state = {
newTitle: '',
list: []
};
}
handleChange(event) {
this.setState(Object.assign({},
this.state,
{ newTitle: event.target.value }));
}
handleSubmit(event) {
this.addBlock(this.state.newTitle);
event.preventDefault();
return false;
}
render() {
return (
<div className="cb-list">
<div>
<form onSubmit={() => this.handleSubmit}>
<input type="text" value={this.state.value} onChange={() => this.handleChange}
placeholder="Enter new title"/>
<input type="submit" value="Submit" />
</form>
</div>
</div>
);
}
addBlock(title) {
let updatedList = this.state.list.concat({ title: title });
this.setState({ list: updatedList })
}
};
$(function() {
ReactDOM.render(<CbList/>, $('#home').get(0));
});
You forgot to invoke the functions:
onSubmit={()=>this.handleSubmit}
should be
onSubmit={()=>this.handleSubmit()}
Or, just pass a reference to the function:
onSubmit={this.handleSubmit}
but you'll need to bind your functions in the constructor (as show in the forms example link):
this.handleSubmit = this.handleSubmit.bind(this);
You need to bind you event handlers on constructor so you can use them among other events.
constructor(props) {
super(props)
this.handleSubmit = this.handleSubmit.bind(this)
this.handleChange = this.handleChange.bind(this)
}
Also, you don't need arrow function when using then as props.
<form onSubmit={this.handleSubmit}>
<input
type="text"
value={this.state.value}
onChange={this.handleChange}
placeholder="Enter new title"
/>
<input type="submit" value="Submit" />
</form>
I am following a react tutorial and trying to re-render the value of a form input field after the user submits the form. However, the value in the input remains in a previous state despite updating the state as shown below.
constructor(props){
super(props);
this.state = { term: '' };
this.onInputChange = this.onInputChange.bind(this);
this.onFormSubmit = this.onFormSubmit.bind(this);
}
render(){
return(
<form onSubmit={this.onFormSubmit} className="input-group">
<input
placeholder="Search Days Forecast"
className="form-control"
value={this.state.value}
onChange={this.onInputChange}
/>
<span className="input-group-btn">
<button type="submit" className="btn btn-secondary"> Submit </button>
</span>
</form>
);
}
onInputChange(event){
this.setState({term: event.target.value});
}
onFormSubmit(event){
event.preventDefault();
this.props.fetchWeather(this.state.term);
this.setState({ term: '' });
}
}function mapDispatchToProps(dispatch){
return bindActionCreators({ fetchWeather }, dispatch);
}
export default connect(null, mapDispatchToProps)(SearchBar);
fetchWeather is just a function that sends a get request.
Any help on why the value field is not re-rendering with the new state will be highly appreciated.
try this
<input
placeholder="Search Days Forecast"
className="form-control"
value={this.state.term}
onChange={this.onInputChange}
/>