Get selected value dropdown React useSate - javascript

Originally, I designed this component to have a useState for each individual input. After realizing that this would not be the best approach for adding new inputs, I refactored to use only one useState. I'm able to get the values for all, but gender. I'm hoping someone could point me in the right direction.
Note: I realize it's not picking up the value because I'm not using person.gender. I went ahead and tried to add value={person.gender = "the value I want"} for each input.
const Forms = () => {
const [person, setPerson] = useState({
firstName: "",
lastName: "",
age: "",
gender: "",
email: "",
});
const [people, setPeople] = useState([]);
const handleChange = (e) => {
const name = e.target.name;
const value = e.target.value;
setPerson({ ...person, [name]: value });
};
const handleSubmit = (e) => {
e.preventDefault();
if (person.firstName && person.lastName && person.age && person.email) {
const newPerson = {
...person,
id: new Date().getTime().toString(),
};
setPeople([...people, newPerson]);
setPerson({
firstName: "",
lastName: "",
age: "",
gender: "",
email: "",
});
}
};
console.log(person.gender);
return (
<article>
<h2>Forms</h2>
<form className="form">
<div className="form-control">
<label htmlFor="firstName">First Name:</label>
<input
type="text"
id="firstName"
name="firstName"
value={person.firstName}
onChange={handleChange}
/>
</div>
<div className="form-control">
<label htmlFor="lastName">Last Name:</label>
<input
type="text"
id="LastName"
name="lastName"
value={person.lastName}
onChange={handleChange}
/>
</div>
<div className="form-control">
<label htmlFor="age">Age:</label>
<input
type="text"
id="age"
name="age"
value={person.age}
onChange={handleChange}
/>
</div>
<div className="form-control">
<label htmlFor="gender">Gender:</label>
<select onChange={handleChange} id="gender">
<option name="gender" value="male">
Male
</option>
<option name="gender" value="female">
Female
</option>
<option name="gender" value="prefer not to answer">
prefer not to answer
</option>
</select>
</div>
<div className="form-control">
<label htmlFor="email">Email:</label>
<input
type="email"
id="email"
name="email"
value={person.email}
onChange={handleChange}
/>
</div>
<button type="submit" className="btn" onClick={handleSubmit}>
Submit
</button>
</form>
{people.map((person) => {
const { firstName, lastName, age, gender, email, id } = person;
return (
<div className="item" key={id}>
<h4>
{firstName} {lastName}
</h4>
<span>{age}</span>
<span>{gender}</span>
<p>{email}</p>
</div>
);
})}
</article>
);
};
export default Forms;
Thanks,
Sean

You have to give the name attribute to the select element, not to its options
<select name="gender" onChange={handleChange} id="gender">

Try reading documentation in react about forms
https://reactjs.org/docs/forms.html
Another thing I think it e.target.value is not working in select form, also you shoud use independent state for every form input because in this layer you cause some effect and rerender

Related

Checkbox value return undefined

Hello guys i have a problem, i have a 2 checkbox, each of them have value. The first checkbox is Any/Not, and the second one is Valid/Invalid. If the checkbox is checked the value will change to Any, if not checked the value will be not, same for the valid/invalid one.
I already tried, but when the checkbox is unchecked the value im getting is undefined. Btw i use react, node, and mysql. But the value is succesfully changed when the box is checked.
Here is the code :
FormDataProvider.js
import React from 'react';
import {createContext, useState} from "react"
export const FormData = createContext();
export default function FormDataProvider({children}) {
const [formData , setFormData] = useState({
cName : "",
Address : "",
phoneNumber : "",
presidentName : "",
managerEmail : "",
managerPhone : "",
picEmail : "",
picPhone : "",
date: "",
mainBusiness : "",
employeeNumber : "",
numberOfCustomer : "",
myFile : "",
any : "" ,
valid : ""
});
return (
<FormData.Provider value={{ formData, setFormData }}>
{children}
</FormData.Provider>
);
}
Form.js
const Form = () => {
let navigate = useNavigate();
Axios.defaults.withCredentials = true;
const { emailLog, setEmailLog } = useContext(EmailUser);
const { loginStatus, setLoginStatus } = useContext(LoginStatus);
const { formData , setFormData} = useContext(FormData);
const handleChange = event => {
if (event.target.checked) {
setFormData({...formData, any : event.target.checked})
} else {
setFormData({...formData, any : "Not"})
}
};
const handleChange2 = event => {
if (event.target.checked) {
setFormData({...formData, valid : event.target.checked})
} else {
setFormData({...formData, valid : "Invalid"})
}
};
return (
<form method='POST' encType='multipart/form-data' action='http://localhost:3001/registration'>
<div className=''>
<input className='inputForm' type='email' value={emailLog} name='email' required onChange={(e) => {
setEmailLog(e.target.value) }} />
<input className='inputForm' type='text' placeholder='Company Name' name="CompanyName" required value={formData.cName} onChange={(event) =>
setFormData({ ...formData, cName: event.target.value })}/>
<input className='inputForm' type='text' placeholder='Address' name="Address" required value={formData.Address} onChange={(event) =>
setFormData({ ...formData, Address: event.target.value })} />
<input className='inputForm' type='tel' placeholder='Phone Number' name="Phone" required value={formData.phoneNumber} onChange={(event) =>
setFormData({ ...formData, phoneNumber: event.target.value })} />
<input className='inputForm' type='text' placeholder='President Director Name' name="PresidentName" required value={formData.presidentName} onChange={(event) =>
setFormData({...formData, presidentName: event.target.value})} />
<input className='inputForm' type='email' placeholder='Manager Email' name="ManagerEmail" required value={formData.managerEmail} onChange={(event) =>
setFormData({...formData, managerEmail: event.target.value})} />
<input className='inputForm' type='tel' placeholder='Manager Phone' name="ManagerPhone" required value={formData.managerPhone} onChange={(event) =>
setFormData({...formData, managerPhone: event.target.value})} />
<input className='inputForm' type='email' placeholder='PIC Email' name="PICEmail" required value={formData.picEmail} onChange={(event) =>
setFormData({...formData, picEmail: event.target.value})} />
<input className='inputForm' type='tel' placeholder='PIC Phone' name="PICPhone" required value={formData.picPhone} onChange={(event) =>
setFormData({...formData, picPhone: event.target.value})} />
<input className='inputForm' type='date' placeholder='Date' name="EstablishedDate" required value={formData.date} onChange={(event) =>
setFormData({...formData, date: event.target.value})} />
<select className='selectBox' name='ChoiceBusiness' required onChange={(event) =>
setFormData({...formData, mainBusiness: event.target.value})} >
<option value="" disabled selected hidden>Choose Main Business...</option>
<option value="Software License">Software License</option>
<option value="IT Services & Consulting">IT Services & Consulting</option>
<option value="IT Outsourcing">IT Outsourcing</option>
<option value="Hardware">Hardware</option>
<option value="General Trading">General Trading</option>
<option value="Others">Others</option>
</select>
<select className='selectBox' name='EmployeeNumber' required onChange={(event) =>
setFormData({...formData, employeeNumber: event.target.value})} >
<option value="" disabled selected hidden>Choose Employee Number...</option>
<option value="1-50">1-50</option>
<option value="51-100">51-100</option>
<option value="101-250">101-250</option>
<option value="251-500">251-500</option>
<option value="500+">500+</option>
</select>
<input className='inputForm' type="number" placeholder='Number of Customer' name="NumberOfCustomer" required value={formData.numberOfCustomer} onChange={(event) =>
setFormData({...formData, numberOfCustomer: event.target.value})} />
<input className='inputFormDate' type="file" name='pdfFiles' multiple required onChange={(event) =>
setFormData({...formData, myFile : event.target.value})} />
<div className='formCheckboxes'>
<div className='formCheckbox'>
<p>SK Menhum & Akta Notaris</p>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" value="Any" name="Any" onChange={handleChange}/>
<label class="form-check-label" for="inlineCheckbox1">Any</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" value="Valid" name="Valid" onChange={handleChange2}/>
<label class="form-check-label" for="inlineCheckbox2">Valid</label>
</div>
</div>
</div>
<button className='btnSubmit' type='submit'> Submit</button>
</div>
</form>
)
}
export default Form
Always use the functional update format to update state based on its previous value to prevent loss of batched state updates.
When checked, you're setting the value to the checked property which is a Boolean. You want the value property instead
Try something like this
setFormData((fd) => ({
...fd,
any: event.target.checked ? event.target.value : "Not",
}));
You could probably use something generic for all inputs provided their name attributes match the object keys you want.
Checkboxes could provide their off value in a data-attribute, eg
<input
class="form-check-input"
type="checkbox"
value="Any"
data-off="None"
name="any"
onChange={handleChange}
/>
// generic handler for all inputs
const handleChange = (e) => {
let value;
switch (e.target.type) {
case "checkbox":
value = e.target.checked ? e.target.value : e.target.dataset.off;
break;
case "file":
value = e.target.files[0];
break;
default:
value = e.target.value;
}
setFormData((fd) => ({
...fd,
[e.target.name]: value,
}));
};

Clear Form Fields in React on Submit

I know this has probably been asked a few times, but I simply cannot figure out how to clear the form fields after submission of the form. It is working perfectly, but all of the data remains in the fields once I submit. I have tried the resetForm but that doesn't seem to be working for me.
Any help is greatly appreciated!
import React from "react";
import axios from "axios";
import '../ticket.min.css'
import Form from 'react-bootstrap/Form'
import Col from 'react-bootstrap/Col'
import Button from 'react-bootstrap/Button'
class Ticket extends React.Component {
state = {
firstName: "",
lastName: "",
email: "",
content: "",
category: "",
urgency: "",
tickets: [],
}
handleChange = (event) => {
this.setState({ [event.target.name]: event.target.value });
};
handleSubmit = (event) => {
event.preventDefault();
this.setState({
firstName: '',
lastName: '',
email: '',
content: '',
category: '',
urgency: '',
})
};
addTicket = () => {
let url = "http://localhost:8080/tickets";
axios.post(url, {
firstName: this.state.firstName,
lastName: this.state.lastName,
email: this.state.email,
content: this.state.content,
category: this.state.category,
urgency: this.state.selectedOption
}).then(response => {
alert('Your ticket has been submitted');
});
};
getData = () => {
let url = "http://localhost:8080/tickets";
axios
.get(url)
.then((response) => this.setState({ tickets: response.data }));
};
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<label>First Name:</label>
<input type="text" name="firstName" value={this.state.firstName} onChange={this.handleChange} />
<br></br>
<label>Last Name:</label>
<input type="text" name="lastName" value={this.state.lastName} onChange={this.handleChange} />
<br></br>
<label>Email:</label>
<input type="text" name="email" value={this.state.email} onChange={this.handleChange} />
<br></br>
<label>
Select a Category:<br></br>
<select value={this.state.category} onChange={(e) => this.setState({ category: e.target.value })}>
<option value="hardware">Hardware</option>
<option value="software">Software</option>
<option value="internet">Internet</option>
<option value="other">Other</option>
</select>
</label>
<label>Please Describe Your Issue:</label>
<br></br>
<textarea value={this.state.content} name="content" onChange={this.handleChange} />
<label>
Select the Urgency Level:<br></br>
<input
type="radio"
name="selectedOption"
value="Urgent"
checked={this.state.selectedOption === "Urgent"}
onChange={this.handleChange}
/>
Urgent<br></br>
<input
type="radio"
name="selectedOption"
value="Normal"
checked={this.state.selectedOption === "Normal"}
onChange={this.handleChange}
/>
Normal<br></br>
<input
type="radio"
name="selectedOption"
value="Low Priority"
checked={this.state.selectedOption === "Low Priority"}
onChange={this.handleChange}
/>
Low Priority
</label>
<button
type="button"
className="btn btn-primary"
onClick={this.addTicket}
>
Submit
</button>
</form>
<h3>Pending Tickets</h3>
<button
type="button"
className="btn btn-primary"
onClick={this.getData}
>
Show Pending
</button>
<ul>
{this.state.tickets.map(p => (
<li key={p.id}>
<b>First Name:</b>{p.firstName} <b>Last Name:</b>{p.lastName} <b>Email:</b>{p.email} <b>Issue:</b>{p.content} <b>Category:</b>{p.category} <b>Urgency:</b>{p.urgency}
</li>
))}
</ul>
</div>
);
}
}
export default Ticket;

Adding array elements through multiple form fields in React

I am working on a quiz app project to learn to react. I came across a situation where I need to store incorrect options in a quiz question in an array. And later pass over the information to the database.
This is an example JSON format.
{
incorrect_answers:["Jeff Bezos","Satya Nadela","Bill Gates"] }
The incorrect answer is an array and the value needs to be inputted through separate text boxes for each incorrect option like this.
option input form
The part where I am stuck is appending them to the array here is my attempt.
export default class CreateQuiz extends Component{
constructor(props){
super(props);
this.onChangedIncorrectAnswer=this.onChangedIncorrectAnswer.bind(this);
this.onSubmit=this.onSubmit.bind(this);
this.state={
incorrect_answers:[]
}
}
onChangedIncorrectAnswer(e){
const option=e.target.value
this.setState({
incorrect_answers:[...this.state.incorrect_answers,option]
});
}
onSubmit(e){
e.preventDefault();
const quiz = {
incorrect_answers:this.state.incorrect_answers
}
console.log(quiz);
axios.post("http://localhost:3000/quizes",quiz)
.then(res=>console.log(res.data));
window.location='/quiz-list';
}
render(){
return (
<div>
<h3>Create New Quiz</h3>
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label>Incorrect Option 1</label>
<input type="text"
required
className="form-control"
value={this.state.incorrect_answers[0]}
onChange={this.onChangedIncorrectAnswer}
/>
</div>
<div className="form-group">
<label>Incorrect Option 2</label>
<input type="text"
required
className="form-control"
value={this.state.incorrect_answers[1]}
onChange={this.onChangedIncorrectAnswer}
/>
</div>
<div className="form-group">
<label>Incorrect Option 3</label>
<input type="text"
required
className="form-control"
value={this.state.incorrect_answers[2]}
onChange={this.onChangedIncorrectAnswer}
/>
</div>
<div className="form-group">
<input type="submit" value="Submit Quiz" className="btn btn-primary"/>
</div>
</form>
</div>
)
}
}
But the form was not working as expected. When I enter content for the first option in the "Option 1" text box only the first character is stored remaining in "Option 2" and so on.
try this, this would work!!
export default class CreateQuiz extends Component {
constructor(props) {
super(props);
this.onChangedCorrectAnswer = this.onChangedCorrectAnswer.bind(this);
this.onChangedIncorrectAnswer = this.onChangedIncorrectAnswer.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.state = {
category: "",
correct_answer: "",
difficulty: "",
type: "",
question: "",
incorrect_answers: ["", "", ""]
};
}
onChangedCorrectAnswer(e) {
this.setState({
correct_answer: e.target.value
});
}
onChangedIncorrectAnswer(e, index) {
const option = e.target.value;
const { incorrect_answers } = this.state;
incorrect_answers[index] = option;
this.setState({
incorrect_answers
});
}
onSubmit(e) {
e.preventDefault();
const quiz = {
category: this.state.category,
correct_answer: this.state.correct_answer,
incorrect_answers: this.state.incorrect_answers,
difficulty: this.state.difficulty,
type: this.state.type,
question: this.state.question
};
console.log(quiz);
axios
.post("http://localhost:3000/quizes", quiz)
.then((res) => console.log(res.data));
window.location = "/quiz-list";
}
render() {
return (
<div>
<h3>Create New Quiz</h3>
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label>Correct Answer</label>
<input
type="text"
required
className="form-control"
value={this.state.correct_answer}
onChange={this.onChangedCorrectAnswer}
/>
</div>
<div className="form-group">
<label>Incorrect Option 1</label>
<input
type="text"
required
className="form-control"
value={this.state.incorrect_answers[0]}
onChange={(e) => this.onChangedIncorrectAnswer(e, 0)}
/>
</div>
<div className="form-group">
<label>Incorrect Option 2</label>
<input
type="text"
required
className="form-control"
value={this.state.incorrect_answers[1]}
onChange={(e) => this.onChangedIncorrectAnswer(e, 1)}
/>
</div>
<div className="form-group">
<label>Incorrect Option 3</label>
<input
type="text"
required
className="form-control"
value={this.state.incorrect_answers[2]}
onChange={(e) => this.onChangedIncorrectAnswer(e, 2)}
/>
</div>
<div className="form-group">
<input
type="submit"
value="Submit Quiz"
className="btn btn-primary"
/>
</div>
</form>
</div>
);
}
}
Your array state is considered as one state only
Why don't you create state on the go when user do any change in the input.
create a state object like
this.state = {incorrect_answers: {}}
In your onChangedIncorrectAnswer
onChangedIncorrectAnswer(e){
const option=e.target.value;
const stateName = e.target.name;
this.setState({
incorrect_answers: {...this.state.incorrect_answers, [stateName]: option }
});
}
use your form element as add name as unique which will be used as state
<div className="form-group">
<label>Incorrect Option 1</label>
<input name="incorrect_answers_0" type="text" required className="form-control" value={this.state.incorrect_answers[incorrect_answers_0]}
onChange={this.onChangedIncorrectAnswer} />
</div>
use that object while saving
onSubmit(e){
let yourIncorrectAnswers = Object.values(this.state.incorrect_answers);
})
}

How to update state with input values

I am trying to write a contact management application that uses react state to store the contact information.
I have two states, one data and the other userData.
The data is supposed to be an object that stores the contact as user enters the contact information while userData would be an array of all the data objects.
But for some reason, I only get one property from the object, It's always the last entered field. I don't know what I am doing wrong. Please help. my code:
const [data, setData] = useState({
firstName: "",
lastName: "",
phoneNumber: "",
address: "",
imag: "",
});
// declear a new state varaible to store data
const [userData, setUserData] = useState([""]);
function handleChange(e) {
let name = e.target.name;
let value = e.target.value;
setData({
[name]: value,
});
}
function handleSubmit(e) {
e.preventDefault();
setUserData([...userData, data]);
}
/*le.log(userData);
}, [userData]);*/
console.log(userData);
return (
<>
<form id="form" className="needs-validation" onSubmit={handleSubmit}>
<div>
<input
className="imgFile"
type="text"
placeholder="First name"
value={data.firstName}
name="firstName"
onChange={handleChange}
/>
<input
className="imgFile"
type="text"
placeholder="Last name"
value={data.lastName}
name="lastName"
onChange={handleChange}
/>
<input
className="imgFile"
type="tel"
placeholder="Phone Number"
value={data.phoneNumber}
name="phoneNumber"
onChange={handleChange}
/>
<input
className="imgFile"
type="email"
placeholder="Email"
value={data.email}
name="email"
onChange={handleChange}
/>
<input
className="imgFile"
type="text"
placeholder="Address"
value={data.address}
name="address"
onChange={handleChange}
/>
<input
type="file"
name="img"
accept="image/*"
value={data.img}
onChange={handleChange}
/>
<button className="contactButton">Save </button>
</div>
</form>
</>
);
}
I have pasted the correct code here , using spread operator the copy of previous data is provided when setData is called so that it's values are not overwritten.
const [data, setData] = useState({
firstName: "",
lastName: "",
phoneNumber: "",
address: "",
imag: "",
});
// declear a new state varaible to store data
const [userData, setUserData] = useState([""]);
function handleChange(e) {
let name = e.target.name;
let value = e.target.value;
setData({
...data,
[name]: value,
});
}
function handleSubmit(e) {
e.preventDefault();
setUserData([...userData, data]);
}
console.log(userData);
return (
<>
<form id="form" className="needs-validation" onSubmit={handleSubmit}>
<div>
<input
className="imgFile"
type="text"
placeholder="First name"
value={data.firstName}
name="firstName"
onChange={handleChange}
/>
<input
className="imgFile"
type="text"
placeholder="Last name"
value={data.lastName}
name="lastName"
onChange={handleChange}
/>
<input
className="imgFile"
type="tel"
placeholder="Phone Number"
value={data.phoneNumber}
name="phoneNumber"
onChange={handleChange}
/>
<input
className="imgFile"
type="email"
placeholder="Email"
value={data.email}
name="email"
onChange={handleChange}
/>
<input
className="imgFile"
type="text"
placeholder="Address"
value={data.address}
name="address"
onChange={handleChange}
/>
<input
type="file"
name="img"
accept="image/*"
value={data.img}
onChange={handleChange}
/>
<button className="contactButton">Save </button>
</div>
</form>
</>
);
}
You are forgetting to spread -data when you are doing this:
setData({
[name]: value,
});
should be this instead:
setData({
...data
[name]: value,
});
So your code is good , the problem is when you use setData you lose everything. In functional components you need to spread the oldData and then change what you like.
Your setData should look like this inside handleChange:
setData(oldData => ({
...oldData,
[name]: value,
}));
Than in your submit form, you don't need at all userData, because you can just use the data object which has all the information you need.
And you can change your handleSubmit like this:
function handleSubmit(e) {
e.preventDefault();
console.log('data',data);
// do whatever with your "data", the object has all the information inside
}

Having issues with my onClick on a registration form

New to react so I apologize if the solution obvious. Working on a registration form that should create a new account on submit using ajax. I know that I'm supposed to use onChange to gather the information is submitted. After seeing a number of examples I am still unable to get my code to work.
I know that the ajax call for POST works because I put in information myself on vscode to test if on submit it will create which it did. I am having issues with the transition from onChange to my submit form. Hope that was clear. Thank you
I've tried creating a onChange function for my registration template. I am unable to get the results that I've been hoping for
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {
payload: {
firstName: "",
lastName: "",
email: "",
password: "",
passwordConfirm: ""
}
};
}
handleChange = event => {
let name = event.target.name;
let value = event.target.value;
this.setState({
[name]: value,
[name]: value,
[name]: value,
[name]: value,
[name]: value
});
};
onClickHandler = evt => {
evt.preventDefault();
let payload = this.state;
console.log(payload);
debugger;
registerService
.register(payload)
.then(this.onActionSuccess)
.catch(this.onActionError);
};
onActionSuccess = response => {
console.log(response);
};
onActionError = errResponse => {
console.log(errResponse);
};
<!-- -->
render() {
return (
<main role="main">
<div className="container">
<h1 id="title" align="center">
Register User
</h1>
</div>
<div className="container">
<div className="col-sm-4 col-sm offset-4">
<form className="form">
<div className="form-group">
<label htmlFor="this.state.firstName">First Name</label>
<input
placeholder="First Name"
type="text"
id="this.state.firstName"
className="form-control"
name="firstName"
value={this.state.firstName}
onChange={this.handleChange}
/>
</div>
<div className="form-group">
<label htmlFor="this.state.lastName">Last Name</label>
<input
placeholder="last Name"
type="text"
id="this.state. lastName"
className="form-control"
value={this.state.lastName}
onChange={this.handleChange}
/>
<div className="form-group">
<label htmlFor="register-email">Email</label>
<input
placeholder="Enter Email"
type="text"
className="form-control"
id="register-email"
value={this.state.email}
onChange={this.handleChange}
/>
</div>
</div>
<div className="form-group">
<label htmlFor="register-password">Password</label>
<input
placeholder="Password"
type="password"
id="register-password"
`enter code here`className="form-control"
value={this.state.password}
onChange={this.handleChange}
/>
</div>
<div className="form-group">
<label htmlFor="register-passwordConfirm">
Confirm Password
</label>
<input
placeholder="Confirm Password"
type="password"
id="register-passwordConfirm"
className="form-control"
value={this.state.passwordConfirm}
onChange={this.handleChange}
/>
</div>
<button onClick={this.onClickHandler} className="btn btn-
primary">
Submit Form
</button>
I am expecting to create a new profile when clicking submit via POST ajax call
Your handleChange function should be
handleChange = event => {
let { name, value } = event.target;
this.setState({
[name]: value,
});
};
You always call your handleChange once at a time. Every time you change something on the input, the function gets different name and different value, which is suffice to add/update the your state.
And I noticed that you also have payload object in state. Modify the state like
this.state = {
firstname: '',
....
}
If you really want to use like
this.state = {
payload: {
firstName: '',
....
}
};
Your onChange function should look like,
handleChange = event => {
let { name, value } = event.target;
this.setState({
payload: {
...this.state.payload, // don't forget to copy all the other values
[name]: value,
}
});
};

Categories

Resources