I am new to Reactjs and just now I have started with React two way binding forms.I have coded for a form, I wanted the form clear after submission.
Even after submission it's not getting clear.
Please point out mistake in the code.
Also check if I have implemented 2 way binding correctly.
Correct me if I am wrong.
ExpenseForm.js
import React, { useState } from "react";
const ExpenseForm = () => {
const [userInput, setuserInput] = useState({enteredTitle : '' , enteredAmount : '',enteredDate : ''});
const TitleChangeHandler = (event) => {
setuserInput((prevState) => {
return { ...prevState, enteredTitle: event.target.value };
});
};
const AmountChangeHandler = (event) => {
setuserInput((prevState) => {
return { ...prevState, enteredAmount: event.target.value };
});
};
const DateChangeHandler = (event) => {
setuserInput((prevState) => {
return { ...prevState, enteredDate: event.target.value };
});
};
const submitHandler = (event) => {
event.preventDefault();
const expenseData = {
title: userInput.enteredTitle,
amount: userInput.enteredAmount,
date: new Date(userInput.enteredDate),
};
console.log(expenseData);
setuserInput({enteredTitle : '' , enteredAmount : '',enteredDate : ''})
console.log(expenseData);
};
return (
<form onSubmit={submitHandler}>
<div className="new-expense__controls">
<div className="new-expense__control">
<label>Title</label>
<input
type="text"
value={setuserInput.enteredTitle}
onChange={TitleChangeHandler}
/>
</div>
<div className="new-expense__control">
<label>Amount</label>
<input
type="number"
value={setuserInput.enteredAmount}
onChange={AmountChangeHandler}
min="0.01"
stepmin="0.01"
/>
</div>
<div className="new-expense__control">
<label>Date</label>
<input
type="date"
value={setuserInput.enteredDate}
onChange={DateChangeHandler}
min="2019-01-01"
max="2022-12-31"
/>
</div>
<div className="new-expense__actions">
<button type="submit">Submit</button>
</div>
</div>
</form>
);
};
export default ExpenseForm;
I don't know what two-way binding is and I'm not quite sure why your inputs aren't resetting, usually when you reset the input's value it changes. But you can call event.target.reset() at the end of your submit handler to reset the form. Also, you can refactor your code to have only one onChangeHandler by assigning each input with a name attribute and then using that name within the onChangeHandler to dictate the key in the 'userInput' object:
const ExpenseForm = () => {
const [userInput, setuserInput] = useState({
enteredTitle: "",
enteredAmount: "",
enteredDate: ""
});
const onChangeHandler = (event) => {
setuserInput((prevState) => {
return { ...prevState, [event.target.name]: event.target.value };
});
};
const submitHandler = (event) => {
event.preventDefault();
const expenseData = {
title: userInput.enteredTitle,
amount: userInput.enteredAmount,
date: new Date(userInput.enteredDate)
};
console.log(expenseData);
setuserInput({ enteredTitle: "", enteredAmount: "", enteredDate: "" });
console.log(expenseData);
event.target.reset();
};
return (
<form onSubmit={submitHandler}>
<div className="new-expense__controls">
<div className="new-expense__control">
<label>Title</label>
<input
name="enteredTitle"
type="text"
value={setuserInput.enteredTitle}
onChange={onChangeHandler}
/>
</div>
<div className="new-expense__control">
<label>Amount</label>
<input
name="enteredAmount"
type="number"
value={setuserInput.enteredAmount}
onChange={onChangeHandler}
min="0.01"
stepmin="0.01"
/>
</div>
<div className="new-expense__control">
<label>Date</label>
<input
name="enteredDate"
type="date"
value={setuserInput.enteredDate}
onChange={onChangeHandler}
min="2019-01-01"
max="2022-12-31"
/>
</div>
<div className="new-expense__actions">
<button type="submit">Submit</button>
</div>
</div>
</form>
);
};
export default ExpenseForm;
Related
I am working on a project using Next JS, and I was trying to write an on Change function that deals with multiple individual files that aren't in an array. This is what I have so far, and the function is named "handleChange":
import { useState, useEffect} from 'react';
import Link from 'next/link';
import React from 'react';
import { withRouter } from 'next/router';
import { getCookie} from '../../actions/auth';
import { createBrand } from '../../actions/brand';
const BrandCreate = ({ router }) => {
const [values, setValues] = useState({
error: '',
sizeError: '',
success: '',
formData: '',
name: '',
address: '',
phone:'',
email:'',
hidePublishButton: false
});
const { error, success, formData, name, address, phone, email} = values;
const token = getCookie('token');
useEffect(() => {
setValues({ ...values, formData: new FormData()});
}, [router]);
const publishBrand = e => {
e.preventDefault();
createBrand(formData, token).then(data => {
if (data.error) {
setValues({ ...values, error: data.error });
} else {
setValues({ ...values, name: '', address:'', phone:'', email:'', error: '', success: `Created Successfully` });
}
});
};
const handleChange = name => e => {
const value = name === 'image' ? e.target.files[0] : e.target.value;
formData.set(name, value);
setValues({ ...values, [name]: value, formData, error: '' });
};
const showError = () => (
<div className="alert alert-danger" style={{ display: error ? '' : 'none' }}>
{error}
</div>
);
const showSuccess = () => (
<div className="alert alert-success" style={{ display: success ? '' : 'none' }}>
{success}
</div>
);
const createBrandForm = () => {
return (
<form onSubmit={publishBrand}>
<div className="formspacing">
<p className="Title">Name</p>
<input type="text" id="Title" value={name} onChange={handleChange('name')} />
<p className="Title">Address</p>
<input type="text" id="Title" value={address} onChange={handleChange('address')} />
<p className="Title">Phone</p>
<input type="text" id="Title" value={phone} onChange={handleChange('phone')} />
<p className="Title">Email</p>
<input type="text" id="Title" value={email} onChange={handleChange('email')} />
<hr className="hrform"/>
<p className="Title">Image</p>
<input id="imgg" onChange={handleChange('logo')} type="file" accept="image/*"/>
<p className="Title">Logo</p>
<input id="imgg" onChange={handleChange('image')} type="file" accept="image/*"/>
</div>
<div className="TwoBtns">
<button type="submit" className="Btn1">PUBLISH</button>
<button type="button" className="cancelbtn"> <Link href="/admin/brands/manageBrands">Back</Link></button>
</div>
</form>
);
};
return (
<React.Fragment>
{createBrandForm()}
<div className="c" width="100px">
{showError()}
{showSuccess()}
</div>
<hr className="hr1" />
</React.Fragment>
);
};
export default withRouter(BrandCreate);
I have another field "logo" that is supposed to also be an image, however I don't know how to handle it in the same function.
If anyone can help me figure this out, I would highly appreciate it.
Thank you in advance!
I have tried this:
const handleChange = name => e => {
const value = name === 'image' ? e.target.files[0] : 'logo' ? e.target.files[0] : e.target.value;
formData.set(name, value);
setValues({ ...values, [name]: value, formData, error: '' });
};
But it doesn't work.
I am trying to edit the input box in a table in a CRUD manner ,but I am unable to update the state and make the input box read-writable.
I am using redux-toolkit to dispatch action for fetching the employee list from json-server.
In the middleware redux-saga is used.
The link to git hub repo:https://github.com/grbknr1996/employee-manager
import React, { useEffect, useState } from "react";
import "./Home.scss";
import { useDispatch, useSelector } from "react-redux";
import { sagaActions } from "../redux/sagaActions";
import { AiOutlineDelete, AiOutlineEdit } from "react-icons/ai";
import { MdDone } from "react-icons/md";
import { FormikBag, useFormik } from "formik";
const Home: React.FC = () => {
const dispatch = useDispatch();
const employees = useSelector((state: any) => state.employees.employees);
const [edit, setEdit] = useState({ edit: false, id: null as any });
const [editInfo, setEditInfo] = useState(employees);
const initialValues = {
id: "",
name: "",
designation: "",
address: "",
};
const formik = useFormik({
initialValues: initialValues,
onSubmit: (values) => {
console.log(JSON.stringify(values, null, 2));
},
});
useEffect(() => {
dispatch({ type: sagaActions.FETCH_EMPLOYEES_SAGA });
}, []);
useEffect(() => {
setInfo();
}, [employees]);
const setInfo = () => setEditInfo(employees);
const handleEdit = (e: React.MouseEvent, index: number) => {
console.log(index);
setEdit({ edit: true, id: index });
};
const handleDelete = (e: React.MouseEvent, index: number) => {
dispatch({ type: sagaActions.DELETE_EMPLOYEE_SAGA, id: index });
};
const toggleEdit = (e: React.FormEvent) => {
console.log("edit toggle");
setEdit({ edit: false, id: null as any });
};
const handleEditChange = (e: any, index: number) => {
setEditInfo(
employees.map((emp: any) =>
emp.id === index ? (emp.name = e.target.value) : emp
)
);
};
return (
<div className="main-container">
<div className="table-container">
<div className="table-row heading">
<div className="row-item">ID</div>
<div className="row-item">NAME</div>
<div className="row-item">DESIGNATION</div>
<div className="row-item">ADDRESS</div>
<div className="row-item">ACTIONS</div>
</div>
{editInfo.map((emp: any, index: number) =>
edit.edit && edit.id === index ? (
<>
<form>
<div className="table-row">
<div className="row-item" key={emp.id}>
{emp.id}
</div>
<input
className="row-item"
name="name"
value={emp.name}
onChange={(e) => handleEditChange(e, index)}
/>
<input className="row-item" value={emp.designation} />
<input className="row-item" value={emp.address} />
<div className="row-item">
<button type="submit">
<MdDone
className="changeColor done"
onClick={(e) => toggleEdit(e)}
/>
</button>
</div>
</div>
</form>
</>
) : (
<div className="table-row">
<div className="row-item" key={emp.id}>
{emp.id}
</div>
<div className="row-item" key={emp.name}>
{emp.name}
</div>
<div className="row-item" key={emp.designation}>
{emp.designation}
</div>
<div className="row-item" key={emp.address}>
{emp.address}
</div>
<div className="row-item">
<AiOutlineEdit
className="changeColor edit"
onClick={(e) => handleEdit(e, index)}
/>
<AiOutlineDelete
className="changeColor delete"
onClick={(e) => handleDelete(e, emp.id)}
/>
</div>
</div>
)
)}
</div>
</div>
);
};
export default Home;
Any will help will be great .Thanks in advance :) .
Instead of value for the input, use defaultValue
<input className="row-item" name="name" defaultValue={emp.name} onChange={(e)=> handleEditChange(e, index)} />
I want to get the value when I change it with onChange and created a name and contact number by using the value and setContacts, this app does not cause error but it does not work, Where is the problem? Thanks.
Each new contact in an object has an id, a name and a phone number
const AddUSer = () => {
const {contacts, setcontacts}=useState([]);
const { userName, setUSerName } = useState("");
const { userPhone, setUserPhone } = useState("");
const setName = (e) => {
const value = e.target.value;
return setUSerName(value);
};
const setPhone = (e) => {
const value = e.target.value;
return setUserPhone(value);
};
const handleNewcontact = () => {
const allcontacts = [...contacts];
const newContact = {
id: Math.floor(Math.random() * 1000),
fullName: userName,
phone: userPhone,
};
allcontacts.push(newContact);
setcontacts(allcontacts);
setUSerName("");
setUserPhone("");
}
};
return (
<div className="container">
<form>
<label>Name</label>
<input className="form-control" onChange={(e) => setName} />
<label>Phone</label>
<input className="form-control" onChange={(e) => setPhone} />
<button
onClick={handleNewcontact}
className="btn btn-primary mt-3 mb-4"
>
Save
</button>
</form>
</div>
);
};
export default AddUSer;
You are not passing the event to the function. You can either do
onChange={(e) => setName(e)}
onChange={(e) => setPhone(e)}
but better:
onChange={setName}
onChange={setPhone}
try this. the values are consoled when the user clicks the submit button.
const AddUSer = () => {
const [contact, setContact] = useState({id: '', userName:'', userPhone:''});
function handleNewContact(event) {
setContact({
...contact, id: Math.floor(Math.random() * 1000),
[event.target.name]: event.target.value
});
}
function handleSubmit(event) {
event.preventDefault();
console.log(contact);
}
return (
<div className="container">
<form>
<label>Name</label>
<input className="form-control" name='userName'
onChange={handleNewContact} />
<label>Phone</label>
<input className="form-control" name='userPhone'
onChange={handleNewContact} />
<button
onClick={handleSubmit}
className="btn btn-primary mt-3 mb-4"
>
Save
</button>
</form>
</div>
);
};
export default AddUSer;
index.js
import React, { useState, useEffect } from 'react';
import Axios from 'axios';
import { ToastContainer, toast } from 'react-toastify';
import { useHistory } from 'react-router-dom';
import 'react-toastify/dist/ReactToastify.css';
const AddRequest = () => {
const [request, setRequest] = useState({
product_name: '',
description: '',
product_img: '',
});
const [error, setError] = useState({
product_error: ''
})
const handleChange = e => {
e.preventDefault();
const {name, value} = e.target;
let formError = {...error};
switch(name) {
case "product_error":
formError.product_error =
value.length < 0 ? "Required" : "";
break;
default:
break;
}
setError({formError, [name]: value});
console.log(error)
setRequest({ ...request, [e.target.name]: e.target.value });
};
const headers = {
'x-access-token': localStorage.getItem('accessToken'),
'content-type': 'multipart/form-data'
}
const handleImageChange = async e => {
e.preventDefault();
setRequest({ ...request, [e.target.name]: e.target.files });
};
const handleSubmit = async e => {
e.preventDefault();
const formData = new FormData()
for (const file of request.product_img) {
formData.append('product_img', file)
}
formData.append('product_name', request.product_name)
formData.append('description', request.description)
await Axios.post(config.api, formData, {
headers: headers
})
.then(res => {
toast.success('Added Successfully!', {
position: "top-right",
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
});
})
.catch(e => {
console.log(e)
toast.error('not Added', {
position: "top-right",
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
});
})
setTimeout(function () {
history.push('/')
}, 1500);
};
return (
<>
<ToastContainer />
<form onSubmit={e => handleSubmit(e)} noValidate>
<div className="form-group">
<label htmlFor='product_name'>Product Name:</label>
<input type="text" name="product_name" id="product_name" placeholder="Enter Product Name" className="form-control" noValidate onChange={e => handleChange(e)} />
{errors.product_error}
</div> =====>>> This is required it must give error if left empty
<div className="form-group">
<label htmlFor='description'>Description:</label>
<input type="text" name="description" id="description" placeholder="Description" className="form-control" onChange={e => handleChange(e)} />
</div>
</div> =====>>> This is required it must give error if left empty
<div className="form-group">
<label htmlFor='product_img'>Product Image:</label> <br />
<input type="file" multiple name="product_img" id="product_img" onChange={e => handleImageChange(e)} />
</div>
<button type="submit" className="btn btn-success"> Add Request Rekko </button>
</form>
</>
)
};
export default AddRequest
Everything is working fine but form validation is not working. I am new to react and tried many things but still, it is not working. Can anyone help me with form validation? I only want all 3 fields to be required. It shows the message that this field is required if someone submits a form without entering anything.
You can simply add the tag required inside the input, like this:
<input type="file" multiple name="product_img" id="product_img" onChange={e => handleImageChange(e)} required />
Little context, I am trying to create a form for for getting User Signup.
I first wrote code as following .
import { useState } from 'react';
const SignupComponent = () => {
const [formData, setFormData] = useState({
name: '',
email: '',
password: '',
error: '',
loading: false,
message: '',
showForm: true
})
const { name, email, password, error, loading, showForm } = formData;
const onChange = e => {
setFormData({ ...formData, error: false, [e.target.name]: e.target.value })
console.log(name)
}
const handleSubmit = async e => {
e.preventDefault();
console.table({ name, email, password, error, loading, showForm })
}
const signupForm = () => {
return (
<form onSubmit={handleSubmit}>
<div className="form-group">
<input type="text" className="form-control" placeholder="Enter Your Name" values={name} onChange={e => onChange(e)} />
</div>
<div className="form-group">
<input values={email} onChange={e => onChange(e)} type="email" className="form-control" placeholder="Enter Your Email" />
</div>
<div className="form-group">
<input values={password} onChange={e => onChange(e)} type="password" className="form-control" placeholder="Enter Your Password" />
</div>
<div>
<button className="btn btn-primary">Signup</button>
</div>
</form>
);
};
return <React.Fragment>{signupForm()}</React.Fragment>};
export default SignupComponent;
I noticed that in this code snippet, the state in setFormData is not getting updated, console logging name or any other value returns a empty string.
result for the above code
But after tweaking the code as such
import { useState } from 'react';
const SignupComponent = () => {
const [formData, setFormData] = useState({
name: '',
email: '',
password: '',
error: '',
loading: false,
message: '',
showForm: true
})
const { name, email, password, error, loading, showForm } = formData;
const handleChange = value => (e) => {
setFormData({ ...formData, error: false, [value]: e.target.value })
console.log(name)
}
const handleSubmit = async e => {
e.preventDefault();
console.table({ name, email, password, error, loading, showForm })
}
const signupForm = () => {
return (
<form onSubmit={handleSubmit}>
<div className="form-group">
<input type="text" className="form-control" placeholder="Enter Your Name" values={name} onChange={handleChange('name')} />
</div>
<div className="form-group">
<input values={email} onChange={handleChange('email')} type="email" className="form-control" placeholder="Enter Your Email" />
</div>
<div className="form-group">
<input values={password} onChange={handleChange('password')} type="password" className="form-control" placeholder="Enter Your Password" />
</div>
<div>
<button className="btn btn-primary">Signup</button>
</div>
</form>
);
};
return <React.Fragment>{signupForm()}</React.Fragment> };
export default SignupComponent;
Makes the code work and result is as desired. As in this image.
2nd way
Why is this behaving like this. Why is the first way not working.
You forgot the name attribute in your inputs, and the value attribute without s
<input name="email" value={email} onChange={onChange} ... />
then
const onChange = e => {
// The event will get passed as an argument even if you don't bind it in onChange={onChange}.
console.log(e.target.name, e.target.value)
setFormData({ ...formData, error: false, [e.target.name]: e.target.value })
}
The event will get passed as an argument.
It works for the second cause you're passing the name as an argument
see docs, https://reactjs.org/docs/thinking-in-react.html
React’s one-way data flow (also called one-way binding) keeps everything modular and fast.
Important thing to solve your question.
The Functional Component(FC) state is changed, UI is re-rendered.
But, your signupForm render function is declared in FC.
So, It is re-delcared as a new, when SignupComponent state is changed.
First. change signupForm render function to FC component.
Second, Pass props to component.
Thrid, re-used them.
import React from 'react'; // React is required to render JSX
const FormInput = ({
type,
placeholder,
value,
onChange,
}) => (
<div className="form-group">
<input type={type} className="form-control" placeholder={placeholder} value={value} onChange={onChange} />
</div>
);
const SignupComponent = () => {
const [formData, setFormData] = React.useState({
name: '',
email: '',
password: '',
error: false,
loading: false,
message: '',
showForm: true,
});
const {
name, email, password, error, loading, showForm,
} = formData;
const handleChange = (value) => (e) => {
setFormData({
...formData,
error: false,
[value]: e.target.value,
});
console.log(name);
};
const handleSubmit = async (e) => {
e.preventDefault();
console.table({
name, email, password, error, loading, showForm,
});
};
return (
<form onSubmit={handleSubmit}>
<FormInput type="text" value={name} placeholder="Enter Your Name" onChange={handleChange('name')} />
<div>
<button type="submit" className="btn btn-primary">Signup</button>
</div>
</form>
);
};
export default SignupComponent;
<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>