React updating the state value in a wrong place - reactjs

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"

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

Form data binding with repeated forms in React

Parent Component
I have a parent component Users with the following snippet:
addUser(index, user) {
var users = this.state.users
var existingUser = users[index]
if (existingUser !== undefined) {
this.updateUser(index, user)
} else {
users.push(user)
this.setState({
users : users
})
}
}
updateUser(index, itemAttributes) {
this.setState({
travellers: [
...this.state.users.slice(0,index),
Object.assign({}, this.state.users[index], itemAttributes),
...this.state.users.slice(index+1)
]
});
}
The updateUser functionality has been taken from React: Updating state when state is an array of objects
And in JSX I have the following snippet:
...
<Form onSubmit={this._handleFormSubmit.bind(this)}>
<UserDetails index={0} callback = {this.addUser.bind(this)}/>
<UserDetails index={1} callback = {this.addUser.bind(this)}/>
<input type="submit" className="btn btn-primary mb-4" value="Continue"/>
</Form>
...
Child Component
Then in the child component UserDetails I have:
handleChange(event) {
event.preventDefault();
let formValues = this.state.formValues;
let name = event.target.name;
let value = event.target.value;
formValues[name] = value;
this.setState({formValues})
this.props.callback(this.props.index, this.state.formValues)
}
And in JSX:
<div className="row">
<div className="col-md-4">
<FormGroup>
<Label>First Name</Label>
<Input type="text" name="firstName" placeholder="First Name" value={this.state.formValues["firstName"]} onChange={this.handleChange.bind(this)} />
</FormGroup>
</div>
<div className="col-md-4">
<FormGroup>
<Label>Last Name</Label>
<Input type="text" name="lastName" placeholder="Last Name" value={this.state.formValues["lastName"]} onChange={this.handleChange.bind(this)} />
</FormGroup>
</div>
</div>
Now I can see two forms, each with a First Name and a Last Name fields. Now the problem is when I enter the First Name for the first user, the First Name for the second user is also automatically set to that of the first user. Thus, I cannot enter separate names for the two users. How can I solve this issue?
I see that you are mutating the state directly by using
let formValues = this.state.formValues;
formValues[name] = value;
One way to alleviate this issue is to spread the formValues before assigning
let formValues = {...this.state.formValues};
or you can use Immer

How do I fix a component is changing from controlled input of the type text to be uncontrolled. Reactjs Error [duplicate]

This question already has answers here:
A component is changing an uncontrolled input of type text to be controlled error in ReactJS
(27 answers)
Closed 3 years ago.
I have set the initial state to blanks than why am I encountering this error ? What should I change next ?
I am fetching users from the database using ID and then trying to update their value. I get this error for the first attempt only. subsequent attempts works perfectly.
could there be problem with the backend ?
import React, { Component } from 'react';
import axios from 'axios';
export default class EditUsers extends Component {
constructor(props)
{
super(props);
this.onchangeUsername = this.onchangeUsername.bind(this);
this.onchangeAddress = this.onchangeAddress.bind(this);
this.onchangePhoneno = this.onchangePhoneno.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.state = {
username:'',
address:'',
phoneno:''
}
}
componentDidMount() {
axios.get('http://localhost:5000/users/'+this.props.match.params.id)
.then(response=>{
this.setState({
username:response.data.username,
address:response.data.address,
phoneno:response.data.phoneno,
})
})
.catch(function (error) {
console.log(error);
})
}
onchangeUsername(e)
{
this.setState({
username:e.target.value
});
}
onchangeAddress(e)
{
this.setState({
address:e.target.value
});
}
onchangePhoneno(e)
{
this.setState({
phoneno:e.target.value
});
}
onSubmit(e){
e.preventDefault();
const user =
{
username:this.state.username,
address:this.state.address,
phoneno:this.state.phoneno
}
console.log(user);
axios.post('http://localhost:5000/users/update/'+this.props.match.params.id,user)
.then(res=>console.log(res.data));
this.setState({
username:this.props.username,
address:this.props.address,
phoneno:this.props.phoneno
})
}
render()
{
return (
<div>
<h3>Edit User List</h3>
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label>Username: </label>
<input type="text" required
className="form-control"
value={this.state.username}
onChange={this.onchangeUsername}
/>
</div>
<div className="form-group">
<label>Address: </label>
<input type="text" required
className="form-control"
value={this.state.address}
onChange={this.onchangeAddress}
/>
</div>
<div className="form-group">
<label>Phoneno: </label>
<input type="text" required
className="form-control"
value={this.state.phoneno}
onChange={this.onchangePhoneno}
/>
</div>
<div className="form-group">
<input type="submit" value="Update" className="btn btn-primary" />
</div>
</form>
</div>
);
}
}
Prevent your input value to be null.
If you pass from null to not null, you will recieve this error.
A quick fix could be to do this:
<input
type="text"
required
className="form-control"
value={this.state.username || ''}
onChange={this.onchangeUsername}
/>

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

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});
}

ReactJS add multiple input fields dynamically

Hello I am new to React and am lost at trying to figure out how to add input field dynamically with React.
If someone can please help me in figuring out how to bind an onclick to add another field dynamically to the form.
How can i click add button and another option input will render
class AddPost extends Component {
static contextTypes = {
router: React.PropTypes.object
};
appendInput() {
var newInput = `input-${this.state.inputs.length}`;
this.setState({ inputs: this.state.inputs.concat([newInput]) });
}
handleFormSubmit(formProps){
this.props.addPost(formProps);
this.context.router.push('/posts');
}
render(){
const {handleSubmit,fields:{title,option}} = this.props;
return (
<div className="row top-buffer">
<div className="col md-auto">
<form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}>
<fieldset className="form-group">
<label>Question:</label>
<input {...title} className="form-control" placeholder="Enter question here"/>
{title.touched && title.error && <div className="text-danger">{title.error}</div>}
</fieldset>
<fieldset className="form-group">
<label>Option:</label>
<input {...option} className="form-control" placeholder="Enter option"/>
{option.touched && option.error && <div className="text-danger">{option.error}</div>}
</fieldset>
<fieldset className="form-group">
<label>Option:</label>
<input {...option} className="form-control" placeholder="Enter option"/>
{option.touched && option.error && <div className="text-danger">{option.error}</div>}
</fieldset>
<button className="btn btn-success">Add</button>
</form>
<button onClick={ () => this.appendInput() }>
CLICK ME TO ADD AN INPUT
</button>
</div>
</div>
);
}
}
function validate(formProps){
const errors = {};
if(! formProps.title){
errors.title = "Title is required";
}
if(! formProps.option){
errors.body = "Option is required";
}
return errors;
}
function mapStateToProps(state){
return {
posts:state.post
}
}
export default reduxForm({
form:'post',
fields:['title','body'],
validate:validate,
},mapStateToProps,{addPost})(AddPost);
If you are using redux-form. Checkout the example with FieldArray, that should help.

Resources