React - Input fields not editable even after I set the state - reactjs

I am trying to type on the inputs but it is not allowing me too. My state changes but it doesn't show.
I am using props to show an event OR and empty event if there is no props (no event selected).
Im sorry but Stack is telling me to add more details but I don't know what else to add, I already described my problem
class EventForm extends PureComponent {
state = {
event: this.props.selectedEvt,
query: ""
};
onFormSubmit = e => {
e.preventDefault();
this.props.addEvent(this.state.event);
};
onInputChange = evt => {
console.log(evt);
evt.persist();
let newEvt = this.state.event;
newEvt[evt.target.name] = evt.target.value;
this.setState({
event: newEvt
});
};
componentDidUpdate(prevProps) {
this.props.selectedEvt &&
this.setState({
event: this.props.selectedEvt
});
}
render() {
const { event } = this.state;
return (
<form className="card" onSubmit={this.onFormSubmit}>
<div className="form-row card-body">
<div className="form-group col-md-12">
<label hmtlfor="inputName">Event Name</label>
<input
name="title"
type="text"
className="form-control"
id="inputEventName"
onChange={this.onInputChange}
value={event.title}
/>
<label hmtlfor="inputDate">Event Date</label>
<input
name="date"
type="date"
className="form-control"
id="inputEventDate"
onChange={this.onInputChange}
value={event.date}
/>
<label hmtlfor="inputDate">Event Time</label>
<input
name="time"
type="time"
className="form-control"
id="inputEventTime"
onChange={this.onInputChange}
value={event.time}
/>
<label hmtlfor="inputAddress">Address</label>
<input
name="address"
type="text"
className="form-control"
id="autocomplete"
onChange={this.onInputChange}
value={event.address}
autoComplete="new-password"
/>
<label hmtlfor="inputHost">Hosted By</label>
<input
name="host"
type="text"
className="form-control"
id="inputHost"
onChange={this.onInputChange}
value={event.host}
/>
<label hmtlfor="inputDesc">Description</label>
<textarea
name="desc"
className="form-control"
rows="5"
id="inputDesc"
wrap="soft"
onChange={this.onInputChange}
value={event.description}
/>
<button type="submit" className="btn btn-primary mt-2">
Submit
</button>
</div>
</div>
</form>
);
}
}
export default EventForm;

Every time input value change componentDidMount run and you reset state to initial state value in componentDidUpdate.
componentDidUpdate(prevProps) {
this.props.selectedEvt &&
this.setState({
event: this.props.selectedEvt // Here is the problem
});
}
Also You mutate state when input change. And because its pureComponent it will not update.
Change onInputChange to
onInputChange = evt => {
let name = evt.target.name;
let value = evt.target.value;
let newEvent = {...this.state.event};
newEvent[name] = value
this.setState({event: newEvent});
}

Related

The react app is returning/printing data for one text input but not for other. I have used the exact same blocks of code but nothing seems to work

import React from 'react'
export default class Login extends React.Component {
handleSubmit=(e)=>
{
e.preventDefault();
console.log('you clikked submit')
}
state={
fName:'',
lName:'',
gender:'',
}
These are the functions i am talking about
i am using setState to set the values input from the textfield.
fnameChange = (e) =>{
this.setState({fName:e.target.value})
}
lnameChange = (e) =>{
this.setState({lName:e.target.value})
}
render() {
return (
<div>
<h1>Login</h1>
<form
onSubmit={this.handleSubmit}
className='add-form' autoComplete="off">
<div className='form-control' >
These are the input fields from where i am calling the functions.
both are coded in exact same way.
I am using tags for printing the data to webpage.
I also tried console logging => onChange, the lastName textfield.
But some how onChange set for lastName textfield is getting fired when i enter value in firstName textfield.
<div>
<label >First Name</label>
<input type='text' name='firstName' onChange={this.fnameChange.bind(this)} required maxLength={10}/>
<h1>{this.state.fName}</h1>
</div>
<div>
<label >Last Name</label>
<input type='text' name='lastName' onChanege={this.lnameChange.bind(this)} required maxLength={10}/>
<h1>{this.state.lName}</h1>
</div>
<div>
<label >Email</label>
<input type='text' name='email' required />
<h1>{this.state.fName}</h1>
</div>
</div>
<div className='form-control form-control-check'>
<p><label>Male</label>
<input type='radio' name='gender' value='male' required/></p>
<p><label>Female</label>
<input type='radio' name='gender' value='female'/></p>
<p><label>Other</label>
<input type='radio' name='gender' value='other'/></p>
</div>
<div className='form-control'>
<input type='submit' value='Login'
className='btn btn-block'
/>
</div>
</form>
</div>
)
}
}
<input type='text' name='lastName' onChanege={this.lnameChange.bind(this)} required maxLength={10}/>
onChanege should be onChange
Multiple problems.
You are resetting your state on each onChange.
You had to consider the previous values and override the state like,
fnameChange = (e) => {
this.setState({...this.state, fName: e.target.value });
};
lnameChange = (e) => {
this.setState({...this.state, lName: e.target.value });
};
You don't need to bind as you are using arrow functions.
You can use the value of state to make your inputs a controlled component.
Example: https://stackblitz.com/edit/react-ts-dufrzd?file=Hello.tsx

React updating the state value in a wrong place

I am trying to implement a simple form validation in React where the length of the name should be more than 1 char long, length of country should be more than 2 char long along with the password. However, the password and the country are getting validated properly. But, the name field isn't getting properly validated. Firstly, it's allowing to submit the name if it's just 1 char long and instead is showing the error in the country's span tag. Also, I am not sure how to implement the logic for email validation. Here is my code:
import React, { Component } from "react";
export default class SignUp extends Component {
constructor(){
super();
this.state={
name:'',
country:'',
email:'',
pass:'',
formErrors:{
nameError:'',
countryError:'',
emailError:'',
passwordError:''
}
}
this.handleChange=this.handleChange.bind(this);
this.handleValidate=this.handleValidate.bind(this);
this.handleSubmit=this.handleSubmit.bind(this);
}
handleChange =(e) =>{
let name=e.target.name;
let value=e.target.value;
this.setState({
[name]:value
})
}
handleValidate= () =>{
let { name,country,email,pass} =this.state;
let nameError, countryError, emailError, passError;
if(!name)
nameError="Missing name"
if(name && name.length<2)
countryError="Length of name should be more than 1 character"
if(!country)
countryError="Missing country"
if(country && country.length<3)
countryError="Length of country should be more than 2 characters"
/* if(!email)
emailError="Email can't be empty"
let lastAtPosi=email.lastIndexOf('#');
let lastDotPosi=email.lastIndexOf('.');
console.log("last # posti"+lastAtPosi);
console.log("Last . posi"+lastDotPosi);
*/
if(!pass)
passError="Password can't be empty"
if(pass && pass.length<6)
passError="Password must be more than 6 characters long"
this.setState({
formErrors:{
nameError:nameError,
countryError:countryError,
// emailError:emailError,
passwordError:passError
}
})
console.log("name "+nameError);
}
handleSubmit= (e) =>{
e.preventDefault();
this.handleValidate();
}
render() {
const { name, country, email, pass, formErrors } = this.state;
return (
<div>
<form>
<h3>Sign Up</h3>
<div className="form-group">
<label>Name</label>
<input type="text" onChange={this.handleChange}name="name"value={name} className="form-control" placeholder="Enter name" />
{formErrors.nameError? <span variant="danger">{formErrors.nameError}</span>:'valid'}
</div>
<div className="form-group">
<label>Country</label>
<input type="text" onChange={this.handleChange}name="country"value={country} className="form-control" placeholder="Enter country" />
{formErrors.countryError? <span variant="danger">{formErrors.countryError}</span>:'valid'}
</div>
<div className="form-group">
<label>Email address</label>
<input type="email" onChange={this.handleChange}name="email"value={email} className="form-control" placeholder="Enter email" />
{formErrors.emailError?<span variant="danger">{formErrors.emailError}</span>:'valid'}
</div>
<div className="form-group">
<label>Password</label>
<input type="password" onChange={this.handleChange}name="pass" value={pass} className="form-control" placeholder="Enter password" />
{formErrors.passwordError?<span variant="danger">{formErrors.passwordError}</span>:'valid'}
</div>
<button onClick={this.handleSubmit}type="submit" className="btn btn-primary btn-block">Sign Up</button>
</form>
</div>
);
}
}
Sandbox linkenter link description here
In your handleValidate, you assign an error to the wrong error variable:
if(name && name.length<2)
countryError="Length of name should be more than 1 character"
It should be:
if(name && name.length<2)
nameError="Length of name should be more than 1 character"

onsubmit gets triggered on every form field change

I am trying to implement simple form which triggers API call on form submit in React.
It blows my mind as when trying the below code:
import React, { Component } from 'react';
import axios from 'axios';
var panelStyle = {
'max-width': '80%',
margin: '0 auto'
}
class DBInject extends Component {
constructor() {
super();
this.formHandler = this.formHandler.bind(this);
this.state = {
formFields: {Id: '',
Name: '',
Payment: "01-10-2019",
Type: '',
Value: 110,
Cycle:'',
Frequency:''
}
}
}
render() {
return(
<div>
<div class="panel panel-primary" style={panelStyle}>
<div class="panel panel-heading">React Forum - Register</div>
<div class="panel panel-body">
<form onsubmit={this.formHandler(this.state.formFields)}>
<strong>Id:</strong> <br /> <input type="text" name="Id" placeholder="123" onChange={(e) => this.inputChangeHandler.call(this, e)} value={this.state.formFields.Id} /> <br />
<strong>Name:</strong> <br /> <input type="text" name="Name" placeholder="me#example.com" onChange={(e) => this.inputChangeHandler.call(this, e)} value={this.state.formFields.Name}/> <br />
<strong>Cycle:</strong> <br /> <input type="text" name="Cycle" placeholder="me#example.com" onChange={(e) => this.inputChangeHandler.call(this, e)} value={this.state.formFields.Cycle} /> <br />
<strong>Frequency:</strong> <br /> <input type="text" name="Frequency" onChange={(e) => this.inputChangeHandler.call(this, e)} value={this.state.formFields.Frequency}/> <br />
<strong>Type:</strong> <br /> <input type="text" name="Type" onChange={(e) => this.inputChangeHandler.call(this, e)} value={this.state.formFields.Type} /> <br />
<strong>Payment:</strong> <br /> <input type="date" name="Payment" onChange={(e) => this.inputChangeHandler.call(this, e)} value={this.state.formFields.Payment}/> <br />
<strong>Value:</strong> <br /> <input type="number" name="Value" onChange={(e) => this.inputChangeHandler.call(this, e)} value={this.state.formFields.Value}/> <br /><br />
<button class="btn btn-primary">Send to database</button>
</form>
</div>
</div>
</div>
);
}
inputChangeHandler(e) {
console.log(e);
let formFields = {...this.state.formFields};
formFields[e.target.name] = e.target.value;
this.setState({
formFields
});
};
formHandler(formFields) {
console.log(formFields);
alert('This button does nothing.');
axios.post('http://127.0.0.1:1880/api','', {headers:formFields})
.then(function(response){
console.log(response);
//Perform action based on response
})
.catch(function(error){
console.log(error);
//Perform action based on error
});
}
}
export default DBInject
formHandler gets called every time InputchangeHandler gets called - which is not my intention.
Is there any other simpler way to do it in React?
Every time you call setState the component re-renders. Your form element is calling the function every time it re-renders. You need to make the following changes:
#Update onsubmit
<form onsubmit={this.formHandler.bind(this)}>
#Reference the formFields directly from the component's state
formHandler() {
const { formFields } = this.state;
You can read more on React forms here:
https://reactjs.org/docs/forms.html
Make sure to reference state from inside the handler function rather than passing it in - as this will make your function re-render every state update.
Form element:
//make sure the "S" in submit is capitalized
<form onSubmit={this.formHandler}>
...Your Form Contents
</form>
Handler function:
formHandler(e) {
e.preventDefault() // stop propagation at the start
// reference state from here with this.state like so:
const { formFields } = this.state;
...Your handler code
}

form is not reset after submit- react js

My form is not reset after submit. Whats wrong ?? I am trying to set the state properties to null after submit.But the input values are not set to null. Iam not getting whats wrong with my code.Help me to solve this issue.
class AddNinja extends Component {
state = {
id: null, name: null, age: null, belt: null
};
handleChange = e => {
this.setState({[e.target.id]: e.target.value });
};
handleSubmit = e => {
e.preventDefault();
this.props.addNijna(this.state);
this.setState({id: null, name: null, age: null, belt: null });
};
render() {
return (
<div>
<h4>Add Ninja</h4>
<form onSubmit={this.handleSubmit}>
<label htmlFor="name">id : </label>
<input type="text" id="id" onChange={this.handleChange} />
<label htmlFor="name">Name : </label>
<input type="text" id="name" onChange={this.handleChange} />
<label htmlFor="age">Age : </label>
<input type="text" id="age" onChange={this.handleChange} />
<label htmlFor="belt">Belt : </label>
<input type="text" id="belt" onChange={this.handleChange} />
<button type="submit" className="btn btn-secondary btn-sm m-2">
Submit
</button>
</form>
</div>
);
}
}
export default AddNinja;
You need your inputs to be controlled, meaning they get their value from state and onChange since the state is changed it is reflected in your component. Also set the values to an empty string instead of null to avoid switching from uncontrolled to controlled components at runtime.
You can learn more about about controlled inputs here: https://reactjs.org/docs/forms.html
As for your code what you need to do is:
class AddNinja extends Component {
state = {
id: null, name: null, age: null, belt: null
};
handleChange = e => {
this.setState({[e.target.id]: e.target.value });
};
handleSubmit = e => {
e.preventDefault();
this.props.addNijna(this.state);
this.setState({id: null, name: null, age: null, belt: null });
};
render() {
const {id, name, age, belt} = this.state;
return (
<div>
<h4>Add Ninja</h4>
<form onSubmit={this.handleSubmit}>
<label htmlFor="name">id : </label>
<input value={id} type="text" id="id" onChange={this.handleChange} />
<label htmlFor="name">Name : </label>
<input value={name} type="text" id="name" onChange={this.handleChange} />
<label htmlFor="age">Age : </label>
<input value={age} type="text" id="age" onChange={this.handleChange} />
<label htmlFor="belt">Belt : </label>
<input value={belt} type="text" id="belt" onChange={this.handleChange} />
<button type="submit" className="btn btn-secondary btn-sm m-2">
Submit
</button>
</form>
</div>
);
}
}
export default AddNinja;

ReactJS Uncaught ReferenceError: onSubmit is not defined

Please help me to understand where I am doing what mistake? I created CustomerForm React Component, which having few form fields. These form fields will add records and in another component will show records into table format.
Every thing is working fine for CustomerForm React Component, but if I am adding onSubmit function than form fields are not loading and I am getting console error as:-
Uncaught ReferenceError: onSubmit is not defined
at new CustomerForm (index.js:32590)
<button type="submit" className="btn btn-primary" onClick={ e => this.onSubmit(e)} > Submit </button>
Also please suggest any better way to write ReactJS code using Props & State...
// Let's import react for creating component
import React from "react";
// Create CustomerForm component
class CustomerForm extends React.Component{
// create constructor function for CustomerForm component
constructor(props){
// call super, so constructor function can connect with CustomerForm component
super(props);
// Use state add object with their property and value
this.state = {
firstName : "",
lastName : "",
phoneNo : "",
issue : "",
}
// Create changeData function
// changeData = e => {
// this.setState({
// [e.target.name] : e.target.value
// });
// };
onSubmit = e => {
e.preventDefault();
console.log(this.state);
}
} // close constructor function
render(){
return(
<form>
<div className="form-group">
<label htmlFor="fname">First name</label>
<input
type="text"
className="form-control"
id="fname"
placeholder="First name"
value={this.state.firstName}
onChange={e => this.setState({ firstName: e.target.value })}
/>
{/* call setState for change firstName value
question - I created changeData function which target name attribute and change value for form fields, but it's not working
onChange={e => this.changeData(e)}
*/}
</div>
<div className="form-group">
<label htmlFor="lname">Last name</label>
<input
type="text"
className="form-control"
id="lname"
placeholder="Last name"
value={this.state.lastName}
onChange={e => this.setState({ lastName: e.target.value })}
/>
{/* call setState for change lastName value */}
</div>
<div className="form-group">
<label htmlFor="phone">Phone no.</label>
<input
type="text"
className="form-control"
id="phone"
placeholder="Phone no."
value={this.state.phoneNo}
onChange={e => this.setState({phoneNo: e.target.value})}
/>
{/* call setState for change phoneNo value */}
</div>
<div className="form-group">
<label htmlFor="issue">Issue</label>
<textarea
className="form-control"
id="issue"
rows="3"
value={this.state.issue}
onChange={e => this.setState({issue: e.target.value})}
>
{/* call setState for change issue value */}
</textarea>
</div>
<button
type="submit"
className="btn btn-primary"
onClick={ e => this.onSubmit(e)}
>
Submit
</button>
</form>
);
}
}
export default CustomerForm;
You're declaring a variable named onSubmit on the constructor and trying to access it with this.onSubmit, like a property.
You can do this in your constructor:
this.onSubmit = e => {
e.preventDefault();
console.log(this.state);
}
The suggestion
A better way to accomplish this is extracting your onSubmit method to a class method, with makes your code more readable and more consistent. Would be something like this:
// Let's import react for creating component
import React from "react";
// Create CustomerForm component
class CustomerForm extends React.Component{
// create constructor function for CustomerForm component
constructor(props){
// call super, so constructor function can connect with CustomerForm component
super(props);
// Use state add object with their property and value
this.state = {
firstName : "",
lastName : "",
phoneNo : "",
issue : "",
}
}
/////////
/// Your submit handler is now a method in the CustomerForm class,
/// so you can access with the keyword "this"
onSubmit(e) {
e.preventDefault();
console.log(this.state);
}
render(){
return(
<form onSubmit={e => this.onSubmit(e)}>
{/* Note that I've changed your handler to form,
is usually better than put on a button, since you're using a form already */}
<div className="form-group">
<label htmlFor="fname">First name</label>
<input
type="text"
className="form-control"
id="fname"
placeholder="First name"
value={this.state.firstName}
onChange={e => this.setState({ firstName: e.target.value })}
/>
{/* call setState for change firstName value
question - I created changeData function which target name attribute and change value for form fields, but it's not working
onChange={e => this.changeData(e)}
*/}
</div>
<div className="form-group">
<label htmlFor="lname">Last name</label>
<input
type="text"
className="form-control"
id="lname"
placeholder="Last name"
value={this.state.lastName}
onChange={e => this.setState({ lastName: e.target.value })}
/>
{/* call setState for change lastName value */}
</div>
<div className="form-group">
<label htmlFor="phone">Phone no.</label>
<input
type="text"
className="form-control"
id="phone"
placeholder="Phone no."
value={this.state.phoneNo}
onChange={e => this.setState({phoneNo: e.target.value})}
/>
{/* call setState for change phoneNo value */}
</div>
<div className="form-group">
<label htmlFor="issue">Issue</label>
<textarea
className="form-control"
id="issue"
rows="3"
value={this.state.issue}
onChange={e => this.setState({issue: e.target.value})}
>
{/* call setState for change issue value */}
</textarea>
</div>
<button
type="submit"
className="btn btn-primary"
>
Submit
</button>
</form>
);
}
}
export default CustomerForm;
Controlled Components
Just one more thing I think it may be helpful to you (I've noted your comment about changeData) so if you not resolve the way to do controlled inputs, this minimalist example may help you, with a onChangeHandler I usually use:
import React from 'react';
export default class MyControlledComponent extends React.Component {
constructor(props){
super(props);
// Initiating the first value for our controlled component
this.state = {
name: ""
}
}
submitHandler(e) {
e.preventDefault();
console.log('Hi, ' + this.state.name + '!');
}
onChangeHandler(e) {
const { name, value } = e.target
/*
Here we using the name property of your input to
increase reuse of this function
*/
this.setState({
[name]: value
});
}
render(){
return (
<div className="my-app">
<form onSubmit={e => this.submitHandler(e)}>
<input type="text"
name="name"
value={this.state.name}
onChange={e => this.onChangeHandler(e)} />
<button>Send!</button>
</form>
</div>
)
}
}
Hope it helps!
Your onSubmit function is not bind either bind it in constructor or use fat arrow properly like
{(return)=>{functionname()}}

Resources