Retrieve value of selectedOption.id - javascript

I want to be able to use the value of selectedOption but use only the id values. Essentially, selectedOption.id. Except when I use selectedOption.id I get undefined.
Why is that? What can I do to change that. I attached an image as a reference to what data I am talking about. This handleChange function occurs in the Select component.
My component output:
My code:
import React, { useState } from 'react';
import Select from 'react-select';
export default function CandidateForm({ handleCreate, job_req_titles }) {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [phone, setPhone] = useState('');
const [facebook, setFacebook] = useState('');
const [github, setGithub] = useState('');
const [linkedin, setLinkedin] = useState('');
const [jobTitle, setJobTitle] = useState('');
const [company, setCompany] = useState('');
const [appJobReq, setAppJobReq] = useState('');
const prepareCandidateObj = () => {
// Prepare the candidate object
let candidate = {
name,
email,
phone,
facebook,
github,
linkedin,
jobTitle,
company,
appJobReq,
};
console.log(candidate);
// Pass in the postNewCandidate from the parent component
// to be called in this component
handleCreate(candidate);
// alert('Candidate Submitted!');
};
const handleChange = (selectedOption) => {
setAppJobReq(selectedOption);
console.log(`Option selected:`, selectedOption);
};
return (
<div className='container'>
<div className='row'>
<label className='name'>Name</label>
</div>
<div className='row'>
<input
className='name-input'
type='text'
placeholder='Carol Caroller'
value={name}
onChange={(e) => setName(e.target.value)}
/>
</div>
<div className='row'>
<label className='email'>Email</label>
</div>
<div className='row'>
<input
className='email-input'
placeholder='example#email.com'
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</div>
<div className='row'>
<label className='phone'>Phone</label>
</div>
<div className='row'>
<input
className='phone-input'
placeholder='(201) 534 2233'
value={phone}
onChange={(e) => setPhone(e.target.value)}
/>
</div>
<div className='row'>
<label className='facebook'>Facebook</label>
</div>
<div className='row'>
<input
className='facebook-input'
placeholder='https://www.facebook.com/DilaonRion/'
value={facebook}
onChange={(e) => setFacebook(e.target.value)}
></input>
</div>
<div className='row'>
<label className='linkedin'>Linkedin</label>
</div>
<div className='row'>
<input
className='linkedin-input'
placeholder='https://www.linkedin.com/DillonRion/'
value={linkedin}
onChange={(e) => setLinkedin(e.target.value)}
></input>
</div>
<div className='row'>
<label className='github'>Github</label>
</div>
<div className='row'>
<input
className='github-input'
placeholder='https://www.github.com/DilonRion/'
value={github}
onChange={(e) => setGithub(e.target.value)}
></input>
</div>
<div className='row'>
<label className='job-title'>Job Title</label>
</div>
<div className='row'>
<input
className='job-title-input'
type='text'
placeholder='Frontend Developer'
value={jobTitle}
onChange={(e) => setJobTitle(e.target.value)}
></input>
</div>
<div className='row'>
<label className='current-company'>Current Company Name</label>
</div>
<div className='row'>
<input
className='current-company-input'
type='text'
placeholder='Obrien LLC'
value={company}
onChange={(e) => setCompany(e.target.value)}
></input>
</div>
<div className='row'>
<label className='job-req'>Applicant Job Req</label>
</div>
<div className='row'>
<div className='job-req-input'>
<Select
className='job-req-select'
value={appJobReq}
onChange={handleChange}
options={job_req_titles}
isMulti
classNamePrefix='select'
/>
</div>
</div>
<div className='row'>
<label className='applied'>Applied or Sourced</label>
<select className='applied-input'>
<option disabled defaultValue>
--
</option>
<option value='1'>Applied</option>
<option value='0'>Sourced</option>
</select>
</div>
<button className='create-button' onClick={prepareCandidateObj}>
Create
</button>
</div>
);
}

Since the isMulti prop passed to the Select component, selectedOption will be an array of the selected option(s). You can use the array map method to get an array that contains only the ids of the selected options, assuming that each option has an id:
const handleChange = (selectedOptions) => {
const selectedOptionIds = selectedOptions.map(option => option.id)
console.log("selected option ids:",
};

Related

Uncaught TypeError: Cannot destructure property when using React context

Hello guys so i tried to make global state so the other page can use the state. The problem is i got an error that says:
Login.js:18 Uncaught TypeError: Cannot destructure property 'emailLog' of '(0 , react__WEBPACK_IMPORTED_MODULE_0__.useContext)(...)' as it is undefined.
Im doing this because i want the email from user after logged in and pass them to another page so that i can display the logged in user.
App.js:
export const EmailUser = React.createContext();
function App() {
Axios.defaults.withCredentials = true;
const [invoice, setInvoice] = useState("");
const [currency, setCurrency] = useState("IDR");
const [myFile, setMyFile] = useState("");
const [emailLog, setEmailLog] = useState("");
return (
<EmailUser.Provider value={{ emailLog, setEmailLog }}>
<div className="App">
<BasicExample />
<div className="formInput">
<form method="POST" encType="multipart/form-data" action="http://localhost:3001/upload">
<div className="textUser"></div>
<input
className="inputForm"
defaultValue={emailLog}
type="email"
disabled
name="email"
/>
<input className="inputForm" type="number" placeholder="Invoice No" name="InvoiceNo" />
<input className="inputForm" type="date" name="Invoice_Date" />
<input className="inputForm" type="text" placeholder="Description" name="Description" />
<select
className="selectBox"
name="Currency"
onChange={(e) => {
setCurrency(e.target.value);
}}
>
<option value="IDR">IDR</option>
<option value="USD">USD</option>
<option value="YEN">YEN</option>
</select>
<input className="inputForm" type="number" placeholder="Amount" name="Amount" />
<input
className="custom-file-upload"
multiple
type="file"
name="DocumentFile"
onChange={(e) => {
setMyFile(e.target.value);
}}
/>
<button className="btnSubmit">Submit</button>
</form>
</div>
</div>
</EmailUser.Provider>
);
}
export default App;
Login.js
const Login = () => {
let navigate = useNavigate();
const { emailLog, setEmailLog } = useContext(EmailUser);
const [passwordLog, setPasswordLog] = useState("");
const [loginStatus, setLoginStatus] = useState("");
Axios.defaults.withCredentials = true;
const login = (e) => {
e.preventDefault();
Axios.post("http://localhost:3001/login", {
email: emailLog,
password: passwordLog,
}).then((response) => {
console.log(response);
if (response.data.message) {
alert(response.data.message);
} else {
setLoginStatus(response.data[0].email);
alert("Redirecting");
navigate("/home");
}
});
};
console.log(emailLog);
useEffect(() => {
Axios.get("http://localhost:3001/login").then((response) => {
if (response.data.loggedIn == true) {
setLoginStatus(response.data.email[0].email);
}
});
});
return (
<div>
<img className="wave" src={Wave} />
<img className="wave2" src={WaveV2} />
<div className="wrapper">
<div className="img">{/* <img src={Background}/> */}</div>
<div className="register-content">
<div className="registerForm">
<img src={Avatar} />
<h2 className="title">Welcome</h2>
<div className="input-div one">
<div className="i">
<i className="fas fa-user">
<GrMail />
</i>
</div>
<div className="div">
<input
type="email"
className="input"
placeholder="Email"
required
onChange={(e) => {
setEmailLog(e.target.value);
}}
/>
</div>
</div>
<div className="input-div pass">
<div className="i">
<i className="fas fa-lock">
<AiFillLock />
</i>
</div>
<div className="div">
<input
type="password"
className="input"
placeholder="Password"
required
onChange={(e) => {
setPasswordLog(e.target.value);
}}
/>
</div>
</div>
Don't have an account ?
<button type="submit" className="btn" onClick={login}>
Login
</button>
</div>
</div>
</div>
</div>
);
};
export default Login;
EmailUser context works only with the components that are children of EmailUser.Provider, and it doesn't seem to be the case for Login component. An easy way is to create a separate component, in some EmailUserProvider.js, like so:
import {createContext, useState} from "react"
export const EmailUser = createContext();
export default function EmailUserProvider({children}) {
const [emailLog, setEmailLog] = useState("");
return (
<EmailUser.Provider value={{ emailLog, setEmailLog }}>
{children}
</EmailUser.Provider>
);
}
And make it wrap all the components that would consume it. If I assume all my components and routes are rendered in App and want the context to be global, I would do so:
<EmailUserProvider>
<App/>
</EmailUserProvider>

React Hooks useState() with Object TypeError: Cannot read property 'name' of undefined

I can't find the solution to this error in my code every time I try to type something in my input field. TypeError: Cannot read property 'name' of undefined
but I've done like the answer in the following post https://stackoverflow.com/a/57519847/16568705 still not work
Here is all code
MultiStepForm.js
import { useForm, useStep } from "react-hooks-helper";
import React from "react";
import { LaporanPolisi } from "./stepForm/LaporanPolisi";
const defaultData = {
laporanPolisi: {
nomorLp: "",
jenisKelamin: 0,
tanggalLp: "",
kerugian: 0,
uraianSingkat: "",
pasalDilanggar: [
{
undangUndang: "",
pasal: ""
}
]
},
pelapor: [],
saksi: [],
korban: [],
terlapor: [],
barangBukti: [],
tkp: {
kodeProvinsi: "",
kodeKabupaten: "",
kodeKecamatan: "",
kodeKelurahan: "",
kodeRT: "",
kodeRW: ""
}
}
const steps = [
{ id: "laporanPolisi" },
{ id: "pelapor" },
{ id: "saksi" },
{ id: "korban" },
{ id: "terlapor" },
{ id: "barangBukti" },
{ id: "tkp" },
{ id: "submit" }
]
export const MultiStepForm = () => {
const [formData, setForm] = useForm(defaultData);
const { step, navigation } = useStep({
steps,
initialStep: 0,
});
const props = { formData, setForm, navigation };
switch (step.id) {
case "laporanPolisi":
return <LaporanPolisi {...props} />;
case "pelapor":
return "Pelapor";
case "saksi":
return "Saksi";
case "korban":
return "Korban";
case "terlapor":
return "Terlapor";
case "barangBukti":
return "Barang Bukti";
case "tkp":
return "TKP";
case "submit":
return "Submit";
default:
return <LaporanPolisi {...props} />;
}
};
LaporanPolisi.js
import React from 'react';
export const LaporanPolisi = ({ formData, setForm, navigation }) => {
const {
laporanPolisi
} = formData;
const handleChange = e => {
const { name, value } = e.target;
console.log(name)
setForm(prevState => ({
...prevState,
laporanPolisi: {
...prevState.laporanPolisi,
[name]: value
}
}));
};
return (
<div className="card">
<div className="card-header">
<h4>Laporan Polisi</h4>
</div>
<div className="card-body">
<div className="row">
<div className="col-md-6">
<div className="form-group">
<label htmlFor="nomorLp">Nomor Laporan</label>
<input onChange={handleChange} id="nomorLp"
placeholder="Nomor Laporan" type="text" className="form-control" name="nomorLp" value={laporanPolisi.nomorLp} />
</div>
</div>
<div className="col-md-6">
<div className="form-group">
<label htmlFor="jenisKelamin">Jenis Kelamin</label>
<select onChange={handleChange} value={laporanPolisi.jenisKelamin} id="jenisKelamin" name="jenisKelamin" className="custom-select">
<option value={0}>Laki-Laki</option>
<option value={1}>Perempuan</option>
</select>
</div>
</div>
{/* <input placeholder="Tanggal Laporan" type="text" className="form-control" name="nomorLp" value={jenisKelamin}></input>
<input placeholder="Kerugian" type="text" className="form-control" name="nomorLp" value={nomorLp}></input>
<input placeholder="Uraian Singkat" type="text" className="form-control" name="nomorLp" value={nomorLp}></input>
<input placeholder="Nomor Laporan" type="text" className="form-control" name="nomorLp" value={nomorLp}></input> */}
</div>
</div>
<pre>
<code>
{JSON.stringify(formData.laporanPolisi)}
</code>
</pre>
</div>
)
}
error Image:
https://imgur.com/a/JC89ykW
thanks before sorry for my bad english.
All react components have to return a component, for example: ...
In your MultiStepForm.js there are only 2 cases meet this requirement.
And this is the way I dealt with input, if you want to update setForm, you can add it in hanldeChange:
export default function BasicExample({ formData, setForm, navigation }) {
const [input1, setInput1] =useState('');
const [input2, setInput2] =useState('');
const handleChange = e => {
e.preventDefault()
console.log(input1)
console.log(input2)
};
return (
<form onSubmit={handleChange}>
<div className="col-md-6">
<div className="form-group">
<label htmlFor="nomorLp">Nomor Laporan</label>
<input onChange={e => setInput1(e.target.value)} id="nomorLp"
placeholder="Nomor Laporan" type="text" className="form-control" name="nomorLp" value={input1} />
</div>
</div>
<div className="col-md-6">
<div className="form-group">
<label htmlFor="jenisKelamin">Jenis Kelamin</label>
<select onChange={e => setInput2(e.target.value)} value={input2} id="jenisKelamin" name="jenisKelamin" className="custom-select">
<option value={0}>Laki-Laki</option>
<option value={1}>Perempuan</option>
</select>
</div>
</div>
<button type="submit"> Summit</button>
</form>
);
}
Resolved
i need to define name like this
https://imgur.com/POGiQ5z
in section Nested Object at https://github.com/revelcw/react-hooks-helper
and then, this is my fullcode after change:
LaporanPolisi.js
import React from 'react';
export const LaporanPolisi = ({ formData, setForm, navigation }) => {
const {
laporanPolisi
} = formData;
const handleSubmit = e => {
e.preventDefault();
};
return (
<div className="card">
<div className="card-header">
<h4>Laporan Polisi</h4>
</div>
<div className="card-body">
<form onSubmit={handleSubmit}>
<div className="row">
<div className="col-md-6">
<div className="form-group">
<label htmlFor="nomorLp">Nomor Laporan</label>
<input onChange={setForm} id="nomorLp"
placeholder="Nomor Laporan" type="text" className="form-control" name="laporanPolisi.nomorLp" value={laporanPolisi.nomorLp} />
</div>
</div>
<div className="col-md-6">
<div className="form-group">
<label htmlFor="jenisKelamin">Jenis Kelamin</label>
<select onChange={setForm} id="jenisKelamin" name="laporanPolisi.jenisKelamin" className="custom-select" value={laporanPolisi.jenisKelamin}>
<option value={0}>Laki-Laki</option>
<option value={1}>Perempuan</option>
</select>
</div>
</div>
<div className="col-md-6">
<button className="btn btn-primary" onClick={() => navigation.previous()} type="button">Previous</button>
</div>
<div className="col-md-6">
<button className="btn btn-primary" onClick={() => navigation.next()} type="button">Next</button>
</div>
{/* <input placeholder="Tanggal Laporan" type="text" className="form-control" name="nomorLp" value={jenisKelamin}></input>
<input placeholder="Kerugian" type="text" className="form-control" name="nomorLp" value={nomorLp}></input>
<input placeholder="Uraian Singkat" type="text" className="form-control" name="nomorLp" value={nomorLp}></input>
<input placeholder="Nomor Laporan" type="text" className="form-control" name="nomorLp" value={nomorLp}></input> */}
</div>
</form>
</div>
<pre>
<code>
{JSON.stringify(laporanPolisi)}
</code>
</pre>
</div>
)
}
thanks everyone for answering my question

ReactJs: Get data from parent URL and pass it to child component

I am sending a form data from a form in reactjs. Some pre inputs from the user have to be sent altogether with the form. I get that data from the URL of the parent file and the form is in the child component.
Parent url:
http://localhost:3000/uploadlist?phmcy=2
I have to get the phmcy value from the URL. (Here the data have to be passed is '2').
parent component:
import Upload froimportm './Upload'
import axios from "axios";
import { Link, withRouter } from "react-router-dom";
import { useLocation } from 'react-router';
export default function Uploadlist() {
let phmcy = (new URLSearchParams(window.location.search)).get("phmcy")
var myphmcy = JSON.stringify(phmcy);
//const phmcyvalue = new URLSearchParams(this.props.location.search);
//const phmcy = phmcyvalue.get('phmcy')
console.log(myphmcy);
const ordersAPI= (url='https://localhost:44357/api/Orders') => {
return {
fetchAll: () => axios.get(url),
create: newRecord => axios.post(url, newRecord),
update: (id, updateRecord) => axios.put(url + id, updateRecord),
delete: id => axios.delete(url+id)
}
}
const addOrEdit = (formData, onSuccess) => {
ordersAPI().create(formData)
.then(res => {
onSuccess();
})
.catch(err => console.log(err.response.data))
}
return (
<div className="row">
<div className="jumbotron jumbotron-fluid py-4 "></div>
<div className="container text">
<h1 className="display-4"> Order Register</h1>
</div>
<div className="col-md-4 offset-3">
<Upload
addOrEdit = {addOrEdit}
myphmcy = {myphmcy}
/>
</div>
<div className="col-md-1">
<div> </div>
</div>
</div>
)
}
Child component: (This is where the form is. I have only included a part)
import React, {useState, useEffect} from 'react';
import myphmcy from './Uploadlist';
//const myphmcy = JSON.stringify(phmcy);
console.log(myphmcy);
const defaultImageSrc = '/images/7.jpg';
const initialFieldValues ={
orderId:0,
dateTime:'',
status:'',
status2:'',
pharmacyName:'',
customerName:'',
patientName:'',
patientAge:'',
address:'',
email:'',
teleNo:'',
customerId:1,
pharmacyId:myphmcy,//data obtaind from the URL have to posted as the pharmacyID when posting.
imageName:'',
imageSrc:'',
imageFile: null
}
export default function Upload(props) {
const {addOrEdit} = props
const {myphmcy} = props
const [values, setValues] = useState(initialFieldValues)
const[errors, setErrors] = useState({})
const handleInputChange= e => {
const {name, value} = e.target;
setValues({
...values,
[name]:value
})
}
const showPreview = e => {
if(e.target.files && e.target.files[0]){
let imageFile = e.target.files[0];
const reader = new FileReader();
reader.onload = x => {
setValues({
...values,
imageFile,
imageSrc : x.target.result
})
}
reader.readAsDataURL(imageFile)
}
else{
setValues({
...values,
imageFile:null,
imageSrc:''
})
}
}
const validate = () => {
let temp = {}
temp.customerName = values.customerName == "" ? false : true;
setErrors(temp)
return Object.values(temp).every(x => x == true)
}
const resetForm = () => {
setValues(initialFieldValues)
document.getElementById('image-uploader').value = null;
}
const handleFormSubmit = e => {
e.preventDefault()
if (validate()){
const formData = new FormData()
formData.append('orderId',values.orderId)
formData.append('dateTime',values.dateTime)
formData.append('status',values.status)
formData.append('status2',values.status2)
formData.append('pharmacyName',values.pharmacyName)
formData.append('customerName',values.customerName)
formData.append('patientName',values.patientName)
formData.append('patientAge',values.patientAge)
formData.append('address',values.address)
formData.append('email',values.email)
formData.append('teleNo',values.teleNo)
formData.append('customerId',values.customerId)
formData.append('pharmacyId',values.pharmacyId)
formData.append('imageName',values.imageName)
formData.append('imageFile',values.imageFile)
addOrEdit(formData, resetForm)
alert("Your file is being uploaded!")
}
}
const applyErrorClass = field => ((field in errors && errors[field] == false) ? ' invalid-field' : '')
return (
<>
<div className="container text-center ">
<p className="lead"></p>
</div>
<form autoComplete="off" noValidate onSubmit={handleFormSubmit}>
<div className="card">
<div className="card-header text-center">Place Your Order Here</div>
<img src={values.imageSrc} className="card-img-top"/>
<div className="card-body">
<div className="form-group">
<input type="file" accept="image/*" className="form-control-file" onChange={showPreview} id="image-uploader"/>
</div>
<div className="form-group">
<input type="datetime-local" className="form-control" placeholder="Date Time" name="dateTime" value={values.dateTime}
onChange={ handleInputChange}/>
</div>
<div className="form-group">
<input className="form-control" placeholder="Enter the prescription items and qty" name="status" value={values.status} onChange={ handleInputChange}/>
</div>
<div className="form-group">
<input className="form-control" placeholder="What are the symptoms?" name="status2" value={values.status2} onChange={ handleInputChange}/>
</div>
<div className="form-group">
<input className="form-control" placeholder="Pharmacy Name" name="pharmacyName" value={values.pharmacyName} onChange={ handleInputChange}/>
</div>
<div className="form-group">
<input className={"form-control" + applyErrorClass('customerName')} placeholder="Your Name" name="customerName" value={values.customerName} onChange={ handleInputChange}/>
</div>
<div className="form-group">
<input className="form-control" placeholder="Patient Name" name="patientName" value={values.patientName} onChange={ handleInputChange}/>
</div>
<div className="form-group">
<input className="form-control" placeholder="Patient Age" name="patientAge" value={values.patientAge} onChange={ handleInputChange}/>
</div>
<div className="form-group">
<input className="form-control" placeholder="Delivery address" name="address" value={values.address} onChange={ handleInputChange}/>
</div>
<div className="form-group">
<input className="form-control" placeholder="Your Email" name="email" value={values.email} onChange={ handleInputChange}/>
</div>
<div className="form-group">
<input className="form-control" placeholder="Contact Number" name="teleNo" value={values.teleNo} onChange={ handleInputChange}/>
</div>
<div className="form-group text-center">
<button type="submit" className="btn btn-light">submit</button>
</div>
</div>
</div>
</form>
</>
)
}
This doesn't work well and I can't post the data. Can some genius help me with this?
Issue
For some reason you import the Uploadlist (the default export/import) and name it myphmcy, save this in the initial state, and then never consume the passed myphmcy prop. This pattern tends to lead to stale state as you need to also handle when the prop values update so you can synchronize the state value.
Solution
Storing passed props is anti-pattern in React, just consume the myphmcy prop directly in the handleFormSubmit submit handler. This ensure you are always using the latest myphmcy props value when submitting the form data.
const handleFormSubmit = e => {
e.preventDefault();
if (validate()) {
const formData = new FormData();
formData.append('orderId', values.orderId);
formData.append('dateTime', values.dateTime);
formData.append('status', values.status);
formData.append('status2', values.status2);
formData.append('pharmacyName', values.pharmacyName);
formData.append('customerName', values.customerName);
formData.append('patientName', values.patientName);
formData.append('patientAge', values.patientAge);
formData.append('address', values.address);
formData.append('email', values.email);
formData.append('teleNo', values.teleNo);
formData.append('customerId', values.customerId);
formData.append('pharmacyId', myphmcy) // <-- use the prop directly
formData.append('imageName', values.imageName);
formData.append('imageFile', values.imageFile);
addOrEdit(formData, resetForm) ;
alert("Your file is being uploaded!");
};
You are getting the myphmcy value from props but setting it outside of the function. So it will set only undefined to the pharmacyId. You need to assign the myphmcy value inside the fnuction.

Maximum update depth exceeded with useEffect & map

I am facing this when I am trying to set form error object. Basically, I want to show the errors below each input field. In response, I am getting an array of objects how do I set to my error object?
Error - Maximum update depth exceeded. This can happen when a component calls setState inside useEffect, but useEffect either doesn't have a dependency array, or one of the dependencies changes on every render.
import axios from "axios";
import React, { useState, useEffect, useCallback } from "react";
import { Link } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { register } from "../actions/userActions";
const Register = () => {
const [countriesList, setCountriesList] = useState("");
const [userRegistration, setUserRegistration] = useState({
firstName: "",
lastName: "",
email: "",
password: "",
fullAddress: "",
city: "",
zipCode: "",
country: "",
phone: "",
terms: true,
});
const [userRegistrationError, setUserRegistrationError] = useState({
firstNameError: "",
lastNameError: "",
emailError: "",
passwordError: "",
fullAddressError: "",
cityError: "",
zipCodeError: "",
countryError: "",
phoneError: "",
termsError: "",
});
const dispatch = useDispatch();
const userRegister = useSelector((state) => state.userRegister);
const { loading, errors, success } = userRegister;
useEffect(() => {
const countries = async () => {
try {
const { data } = await axios.get(
`https://restcountries.eu/rest/v2/all`
);
setCountriesList(data);
} catch (err) {
console.error(err);
}
};
countries();
}, []);
useEffect(() => {
const handleErrors = (errors) => {
errors.map((error) => {
if (error.param === "firstname") {
setUserRegistrationError({
...userRegistrationError,
firstNameError: error.msg,
});
}
if (error.param === "email") {
setUserRegistrationError({
...userRegistrationError,
emailError: error.msg,
});
}
return null;
});
};
if (errors) {
handleErrors(errors);
}
}, [errors, setUserRegistrationError]);
const handleChange = (e) => {
const name = e.target.name;
const value = e.target.value;
setUserRegistration({ ...userRegistration, [name]: value });
};
const handleChkChange = (e) => {
const checked = e.target.checked;
console.log(checked);
setUserRegistration({ ...userRegistration, terms: checked });
};
const handleSubmit = (e) => {
e.preventDefault();
try {
dispatch(register());
} catch (error) {
console.error(error);
}
};
return (
<div className="form_container">
<form action="" onSubmit={handleSubmit}>
<div className="row no-gutters">
<div className="col-6 pr-1">
<div className="form-group">
<div className="form-group">
<input
type="text"
name="firstName"
className="form-control"
placeholder="First Name*"
value={userRegistration.firstName}
onChange={handleChange}
/>
<p className="form-vald-error">
{userRegistrationError.firstNameError &&
userRegistrationError.firstNameError}
</p>
</div>
</div>
</div>
<div className="col-6 pr-1">
<div className="form-group">
<input
type="text"
className="form-control"
name="lastName"
placeholder="Last Name*"
value={userRegistration.lastName}
onChange={handleChange}
/>
<p className="form-vald-error">
{userRegistrationError.lastNameError &&
userRegistrationError.lastNameError}
</p>
</div>
</div>
</div>
<hr />
<div className="private box">
<div className="row no-gutters">
<div className="col-6 pr-1">
<div className="form-group">
<input
type="email"
className="form-control"
name="email"
id="email_2"
placeholder="Email*"
value={userRegistration.email}
onChange={handleChange}
/>
<p className="form-vald-error">
{userRegistrationError.emailError &&
userRegistrationError.emailError}
</p>
</div>
</div>
<div className="col-6 pl-1">
<div className="form-group">
<input
type="password"
className="form-control"
name="password"
id="password_in_2"
placeholder="Password*"
value={userRegistration.password}
onChange={handleChange}
/>
<p className="form-vald-error">
{userRegistrationError.passwordError &&
userRegistrationError.passwordError}
</p>
</div>
</div>
<div className="col-12">
<div className="form-group">
<input
type="text"
name="fullAddress"
className="form-control"
placeholder="Full Address*"
value={userRegistration.fullAddress}
onChange={handleChange}
/>
<p className="form-vald-error">
{userRegistrationError.fullAddressError &&
userRegistrationError.fullAddressError}
</p>
</div>
</div>
</div>
{/* /row */}
<div className="row no-gutters">
<div className="col-6 pr-1">
<div className="form-group">
<input
type="text"
className="form-control"
placeholder="City*"
name="city"
value={userRegistration.city}
onChange={handleChange}
/>
<p className="form-vald-error">
{userRegistrationError.cityError &&
userRegistrationError.cityError}
</p>
</div>
</div>
<div className="col-6 pl-1">
<div className="form-group">
<input
type="text"
className="form-control"
placeholder="Postal Code*"
name="zipCode"
value={userRegistration.zipCode}
onChange={handleChange}
/>
<p className="form-vald-error">
{userRegistrationError.zipCodeError &&
userRegistrationError.zipCodeError}
</p>
</div>
</div>
</div>
{/* /row */}
<div className="row no-gutters">
<div className="col-6 pr-1">
<div className="form-group">
<div className="custom-select-form">
<select
className="wide add_bottom_10 form-control"
name="country"
id="country"
value={userRegistration.country}
onChange={handleChange}
>
<option>Country*</option>
{countriesList &&
countriesList.map((country) => (
<option
key={country.alpha2Code}
value={country.alpha2Code}
>
{country.name}
</option>
))}
</select>
<p className="form-vald-error">
{userRegistrationError.countryError &&
userRegistrationError.countryError}
</p>
</div>
</div>
</div>
<div className="col-6 pl-1">
<div className="form-group">
<input
type="text"
className="form-control"
placeholder="Telephone *"
name="phone"
value={userRegistration.phone}
onChange={handleChange}
/>
<p className="form-vald-error">
{userRegistrationError.phoneError &&
userRegistrationError.phoneError}
</p>
</div>
</div>
</div>
{/* /row */}
</div>
<hr />
<div className="form-group">
<label className="container_check">
Accept <Link to="#0">Terms and conditions</Link>
<input
type="checkbox"
name="terms"
checked={userRegistration.terms}
onChange={handleChkChange}
/>
<span className="checkmark" />
<p className="form-vald-error">
{userRegistrationError.termsError &&
userRegistrationError.termsError}
</p>
</label>
</div>
<div className="text-center">
<input
type="submit"
defaultValue="Register"
className="btn_1 full-width"
/>
</div>
</form>
</div>
);
};
export default Register;
your effect depends on userRegistrationError which is an object, reference based. Each time useEffect runs,setUserRegistrationError
creates a new object reference, which leads to an infinite loop since references won't be the same as the previous one.
One approach to avoid this issue and keep the right references, is to pass a callback function to setUserRegistrationError instead than a value. This way userRegistrationError is no longer a dependency, it will be an argument to your function instead:
useEffect(() => {
const handleErrors = (errors) => {
errors.forEach((error) => {
if (error.param === "firstName") {
// here you pass a callback function instead, and userRegistrationError is no longer a dependency
// and returns the next state as expected
setUserRegistrationError(userRegistrationError => ({
...userRegistrationError,
firstNameError: error.msg,
}));
}
if (error.param === "email") {
setUserRegistrationError(userRegistrationError => ({
...userRegistrationError,
emailError: error.msg,
}));
}
});
};
if (errors) {
handleErrors(errors);
}
}, [errors, setUserRegistrationError]);
You have a problem with the second useEffect, the first time you update your state userRegistrationError, the component re-rendered and re-executed the useeffect because the dependency userRegistrationError has changed and the process gets repeated again because the state gets updated every render.
useEffect(() => {
const handleErrors = (errors) => {
errors.map((error) => {
if (error.param === "firstname") {
setUserRegistrationError({
...userRegistrationError,
firstNameError: error.msg,
});
}
if (error.param === "email") {
setUserRegistrationError({
...userRegistrationError,
emailError: error.msg,
});
}
return null;
});
};
if (errors) {
handleErrors(errors);
}
}, [errors, setUserRegistrationError ]); //replace userRegistrationError by setUserRegistrationError

How to write inside input after making it editable?

I Am populating values of my input field from JSON data what am getting from back-end, now there is an edit button on UI by on click on that button I am enabling my input field but not able to type inside as I am setting some value
I want to write inside the input once I have made them editable.
const { register, handleSubmit, errors } = useForm();
const [disabled, setdisabled] = useState(false);
const [editBtn, seteditBtn] = useState(true);
<form onSubmit={handleSubmit(onSubmit)}>
{editBtn === true && (
<div align="right">
<button
className="btn white_color_btn"
type="button"
onClick={edit}
>
Edit
</button>
</div>
)}
{editBtn === false && (
<button className="btn white_color_btn" type="submit">
Save
</button>
)}
<div className="row">
<div className="form-group col-6 col-sm-6 col-md-6 col-lg-4 col-xl-4">
<input
type="text"
disable
id="firstName"
name="firstName"
value={dataItems.firstname}
disabled={disabled ? "" : "disabled"}
ref={register({ required: true })}
/>
{errors.firstname && (
<span className="text-danger">first name required</span>
)}
<br />
<label htmlFor="emp_designation">First name</label>
</div>
<div className="form-group col-6 col-sm-6 col-md-6 col-lg-4 col-xl-4">
<input
type="text"
disabled
id="lastname"
name="lastname"
value={dataItems.lastname}
disabled={disabled ? "" : "disabled"}
ref={register({ required: true })}
/>
{errors.lastname && (
<span className="text-danger">last name required</span>
)}
<br />
<label htmlFor="lastname">Lastname</label>
</div>
</div>
</form>
On click of edit
const edit = () => {
setdisabled(true);
};
Code sandbox
You need to make your input as a controlled component and write onChange handlers which will update the state. This will allow you to edit the input field values. Demo
const [disabled, setdisabled] = useState(false);
const [name, setName] = useState(empData.item.name) // setting default name
const [lastname, setLastname] = useState(empData.item.lastname) // default lastname
const edit = () => {
setdisabled(true);
};
return (<div className="container-fluid">
<div align="right">
<button className="btn" onClick={edit}>
Edit
</button>
</div>
<div className="row">
<div>
<input
type="text"
disable
id="item.value"
value={name}
onChange={(e) => {
setName(e.target.value)
}}
disabled={disabled ? "" : "disabled"}
/>
<br />
<label htmlFor="name">Name</label>
</div>
<div>
<input
type="text"
disabled
id={"lastname"}
value={lastname}
onChange={(e) => {
setLastname(e.target.value)
}}
disabled={disabled ? "" : "disabled"}
/>
<br />
<label htmlFor="lastname">Lastname</label>
</div>
</div>
</div>);
Your input is controlled by the value you are giving to it. ie: Its value is always for example empData.item.name.
And you are not providing a change handler to handle the change.
Try adding something like this:
function myChangeHandler(e){
setEditedValueSomeHow(e.target.value);
}
<input
// ...
onChange={myChangeHandler}
/>
Read more about uncontrolled components
PS: you should have had a warning message in your console like this one:
Edit:
You are using react-hook-form to manage your form but at the same time giving values to your inputs.
Please refer to this link to initialize your form values.
short story:
Remove value form your input.
Pass an object to useForm hook containing initial values.
const { register, handleSubmit, errors } = useForm({
defaultValues: {
firstName: "steve",
lastname: "smith"
}
});
Here is a working fork for your codesandbox
In order to make the input editable, you need to update a local state which controlls the input value. As suggested by you in the comments, you are using graphql to get the data, you can make use of useEffect to set the data in state and then on click of edit, update the localState
export default function App() {
const { register, handleSubmit, errors } = useForm();
const [disabled, setdisabled] = useState(true);
const [editBtn, seteditBtn] = useState(true);
const { loading, data } = useQuery("some qraphql query here"); // getting data from graphql
const [formData, setFormData] = useState({});
useEffect(() => {
setFormData(data);
}, [data]);
const edit = () => {
setdisabled(false);
seteditBtn(false);
};
const onSubmit = () => {
console.log(formData);
// submit data using formData state.
};
const handleChange = e => {
const name = e.target.name;
const value = e.target.value;
console.log(name, value);
setFormData(prev => ({ ...prev, [name]: value }));
};
return (
<div className="container-fluid">
<form onSubmit={handleSubmit(onSubmit)}>
{editBtn === true && (
<div align="right">
<button
className="btn white_color_btn"
type="button"
onClick={edit}
>
Edit
</button>
</div>
)}
{editBtn === false && (
<button className="btn white_color_btn" type="submit">
Save
</button>
)}
<div className="row">
<div className="form-group col-6 col-sm-6 col-md-6 col-lg-4 col-xl-4">
<input
type="text"
id="firstname"
name="firstname"
onChange={handleChange}
value={formData.firstname}
disabled={disabled}
ref={register({ required: true })}
/>
{errors.firstname && (
<span className="text-danger">first name required</span>
)}
<br />
<label htmlFor="emp_designation">First name</label>
</div>
<div className="form-group col-6 col-sm-6 col-md-6 col-lg-4 col-xl-4">
<input
type="text"
id="lastname"
name="lastname"
value={formData.lastname}
onChange={handleChange}
disabled={disabled}
ref={register({ required: true })}
/>
{errors.lastname && (
<span className="text-danger">last name required</span>
)}
<br />
<label htmlFor="lastname">Lastname</label>
</div>
</div>
</form>
</div>
);
}
Working mock demo

Categories