Get values from form with React and Axios - javascript

** Hi, I'm having issues to get the values from my form inputs in a post request. The post request works, I don't get any errors, but I can't save what I type in each field. I get an error that says data hasn't been defined. I've added value={addPub.name} (to each of them with their correspondent name) but still doesn't work. Any help would be very much appreciated, thanks in advance**
function AddPub() {
const [addPub, setAddPub] = useState({
name: "",
email: "",
phone: "",
group: ""
})
const handleChange=e=> {
const {name, value}=e.target
setAddPub(prevState=>({
...prevState,
[name]: value
}))
console.log(addPub)
}
const postPub=async()=> {
await axios.post("http://dev.pubmate.io/pubmate/api/0.1/pub", addPub )
.then(
response=>{
console.log(response)
//setAddPub(data.concat(response.data)). --> Currently commented out due to error with data
})
}
useEffect(async()=> {
await postPub()
}, [])
return (
< div className="addpub">
<h1>Pub Information</h1>
<div className="addpub__container">
<button className="addpub__buttonName" onClick={openForm("name")}>Pub Details<span className="arrow">▼</span></button>
<div id="Name" className="form" style={{display: "block"}}>
<form className="addpub__form">
<TextField className="addpub__input" value={addPub.name} name="name" label="Name" onChange={handleChange}/>
<br />
<TextField className="addpub__input" value={addPub.email} name="email" label="Email" onChange={handleChange}/>
<br />
<TextField className="addpub__input" value={addPub.phone} name="phone" label="Phone" onChange={handleChange}/>
<br />
<TextField className="addpub__input" value={addPub.group} name="group" label="Group" onChange={handleChange}/>
<br />
<div className="addpub__buttons addpub__buttons_name">
<button className="addpub__save" onClick={postPub}>SAVE</button>
<Link className="addpub__cancel" to="/">CANCEL</Link>
</div>
</form>
</div>
}

You are destructuring your values inside handleChange. But you are not passing that value from the TextField to your actual handleChange function.
Try this for each of the TextField:
<TextField className="addpub__input" value={addPub.name} name="name" label="Name" onChange={(e) => handleChange(e) }/>
<TextField className="addpub__input" value={addPub.email} name="email" label="Email" onChange={(e) => handleChange(e) }/>
<TextField className="addpub__input" value={addPub.phone} name="phone" label="Phone" onChange={(e) => handleChange(e) }/>
<TextField className="addpub__input" value={addPub.group} name="group" label="Group" onChange={(e) => handleChange(e) }/>
You should also try to refactor your useEffect to:
useEffect(() => {
;(async () => await postPub())()
}, [])
As a suggestion. If you'd like to try another option. FORMIK is a great tool.

Related

How to get checkbox value using React

I ve got a form consisits of two inputs (emain, password) and one checkbox. Code is here:
<Box component="form" onSubmit={handleSubmit} noValidate sx={{ mt: 1 }}>
<TextField
margin="normal"
required
fullWidth
id="email"
label="Email adress"
name="email"
autoComplete="email"
autoFocus
/>
<TextField
margin="normal"
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
autoComplete="current-password"
/>
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
label="Remember me"
/>
<Button
type="submit"
fullWidth
variant="contained"
sx={{ mt: 3, mb: 2 }}
>
Sign in
</Button>
</Box>
To get the values of Email and Password I use smth.like:
const handleSubmit = (event) => {
event.preventDefault();
const data = new FormData(event.currentTarget);
console.log({
email: data.get('email'),
password: data.get('password'),
});
};
But what's the best practice to get the value of checkbox "Remember me" (in FormControlLabel)? Of course, I can make a new function to handle the changes of checkbox like:
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
onChanges = {newFunction}
label="Remember me"
/>
But I think that's it's not a good idea, because I don't need to get all the changes of this checkbox, I just need to know the value of this checkbox in the moment of submitting the form.
As you pointed out, you can make the checkbox controlled with a React state, but it's not needed if you are inside a form, since the form owns the info of each input element inside of it, but in order to do that you must set a name attribute on each input element, then you can read the values by instantiating a FormData:
const handleSubmit = (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const data = formData.entries();
for (const entry of data) console.log(entry);
};
A working example here: https://stackblitz.com/edit/react-ictfjr
You should use Usestate hooks
Handling a multiple CheckBox : Link
import React, {useState} from 'react'
export default () => {
const [fName, setfName] = useState('');
const [lName, setlName] = useState('');
const [phone, setPhone] = useState('');
const [email, setEmail] = useState('');
const [isChecked, setIsChecked] = useState(false);
const handleOnChange = () => {
setIsChecked(!isChecked);
};
const submitValue = () => {
const frmdetails = {
'First Name' : fName,
'Last Name' : lName,
'Phone' : phone,
'Email' : email
}
console.log(frmdetails);
}
return(
<>
<hr/>
<div className="topping">
<input
type="checkbox"
id="topping"
name="topping"
value="Paneer"
checked={isChecked}
onChange={handleOnChange}
/>
Paneer
</div>
<input type="text" placeholder="First Name" onChange={e => setfName(e.target.value)} />
<input type="text" placeholder="Last Name" onChange={e => setlName(e.target.value)} />
<input type="text" placeholder="Phone" onChange={e => setPhone(e.target.value)} />
<input type="text" placeholder="Email" onChange={e => setEmail(e.target.value)} />
<button onClick={submitValue}>Submit</button>
</>
)
}

Resetting React Form values after validation

have that problem with resetting the values of the input fields in the form. and wanted to ask if somebody knows a better and way to do that instead of just making 'useState' for every field...
const handleSubmit = (e) => {
e.preventDefault();
emailjs.sendForm('sample_id', 'someother_id', formRef.current, 'user_is')
.then((result) => {
console.log(result.text);
}, (error) => {
console.log(error.text);
});
setMessage(true);
setEmail("");
setName("");
setSubject("");
setTextarea("");
};
return (
<div className="contact" id="contact">
<div className="left">
<img src="" alt="" />
</div>
<div className="right">
<h2>Kontakt</h2>
<form ref={formRef} onSubmit={handleSubmit}>
<label>Name</label>
<input onChange={(e) => setName(e.target.value)} type="text" placeholder="Name" name="user_name" value={name} />
<label>Email</label>
<input onChange={(e) => setEmail(e.target.value)} type="email" placeholder="Email" name="user_email" value={email} />
<label>Betreff</label>
<input onChange={(e) => setSubject(e.target.value)} type="text" placeholder="Subject" name="user_subject" value={subject} />
<label>Nachricht</label>
<textarea onChange={(e) => setTextarea(e.target.value)} placeholder="Message" name="message" value={textarea} />
<button type="submit">Send</button>
{message && <span>Thanks we will respond ASAP.</span>}
</form>
</div>
</div>
)
}
You could use a single state for all the form values (kinda like we did before functional components)
// this could be outside your component
const initialState = { email: "", name: "", subject: "", textArea: ""};
// declaring your state
const [formState, setFormState] = React.useState(initialState);
and then
const handleSubmit = (e) => {
e.preventDefault();
emailjs.sendForm('sample_id', 'someother_id', formRef.current, 'user_is')
.then((result) => {
console.log(result.text);
}, (error) => {
console.log(error.text);
});
setMessage(true);
setFormState(initialState)
};
You also would have to rewrite your input handlers. Like that :
<input onChange={(e) => setFormState({...formState, name: e.target.value})} type="text" placeholder="Name" name="user_name" value={name} />

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
}

How to get input values and set it to state on click and console log it for react

I am trying to get the user inputs on click and set it to the state to try and display it on console but every time the button is clicked, the state properties are just empty.
For example.
This is what I want to see in console log
but I just get:
Empty state properties
here is my code
class WalkInBook extends Component {
constructor(props)
{
super(props);
this.state={
firstName:'',
lastName:'',
phone:'',
email:'',
course:'',
};
}
handleClick = () =>
{
console.log(this.state);
}
handleChangeText(event){
const target = event.target;
const value = target.value;
const name = target.name;
this.setState({
[name]:value
})
}
render() {
console.log(this.state);
//
// MATERIAL-UI REQUIREMENT #2: Needed for accessing "styles" CB function declared above this class.
const { classes } = this.props;
return (
<div align="center">
<Typography>
<div>
<div className={classes.root} noValidate autoComplete="off">
<TextField onChangeText={this.handleChangeText} id="standard-basic" name="firstName" label="First Name" />
</div>
<div className={classes.root} noValidate autoComplete="off">
<h1>{this.state.data}</h1>
<TextField id="standard-basic" name="lastName" label="Last Name" />
</div>
<div className={classes.root} noValidate autoComplete="off">
<TextField id="standard-basic" name="phone" label="Phone" />
</div>
<div className={classes.root} noValidate autoComplete="off">
<TextField id="standard-basic" name="email" label="Email" />
</div>
<div className={classes.root} noValidate autoComplete="off">
<TextField id="standard-basic" name="course" label="Course" />
</div>
</div>
<div className={classes.root} noValidate autoComplete="off">
<Button type="submit" onClick={this.handleClick} variant="outlined">Submit</Button>
</div>
</Typography>
</div>
);
}
}
See this full minimal complete verifiable example (https://stackoverflow.com/help/mcve | https://stackoverflow.com/help/how-to-ask)
CodePen demo: https://codepen.io/Alexander9111/pen/OJVyRvm
With all code necessary to demonstrate what was asked:
class WalkInBook extends React.Component {
constructor(props) {
super(props);
this.state = {
firstName:'',
lastName:'',
phone:'',
email:'',
course:''
};
//These lines are important!
this.handleClick = this.handleClick.bind(this);
this.handleChangeText = this.handleChangeText.bind(this);
}
componentDidMount(){
}
handleClick() {
console.log(this.state);
}
handleChangeText(event){
const target = event.target;
const value = target.value;
const name = target.name;
console.log('change', name, value);
this.setState({
...this.state,
[name] : value
})
}
render() {
return (
<div>
<input type="text" onChange={this.handleChangeText} name="firstName" placeholder="firstName"/>
<input type="text" onChange={this.handleChangeText} name="lastName" placeholder="lastName"/>
<input type="text" onChange={this.handleChangeText} name="phone" placeholder="phone"/>
<input type="text" onChange={this.handleChangeText} name="email" placeholder="email"/>
<input type="text" onChange={this.handleChangeText} name="course" placeholder="course"/>
<button type="submit" onClick={this.handleClick} variant="outlined">Submit</button>
</div>
);
}
}
ReactDOM.render(
<WalkInBook />,
document.getElementById('root')
);
You need to bind this i.e. .bind(this) to your onChange onClick event handlers.
Also, you need to use the spread operator to make a copy of your existing state and then modify your one new property:
this.setState({
...this.state,
[name] : value
})
And if you wanted to do it with a functional component And also iterate over the state to generate the input tags then look at this (https://codepen.io/Alexander9111/pen/VwLPKvP):
function WalkInBook(props) {
const initState = {
firstName:'',
lastName:'',
phone:'',
email:'',
course:''
};
const [state, setState] = React.useState(initState);
function handleClick() {
console.log(state);
}
function handleChangeText(event){
const target = event.target;
const value = target.value;
const name = target.name;
console.log('change', name, value);
setState({
...state,
[name] : value
})
}
const handle = handleChangeText;
const output = Object.keys(state).map(function (key) {
//console.log(key)
return <input type="text" onChange={handle} name={key} placeholder={key}/>;
});
return (
<div>
{
output.map((child, index) => {return child})
}
<button type="submit" onClick={handleClick} variant="outlined">Submit</button>
</div>
);
}
ReactDOM.render(
<WalkInBook />,
document.getElementById('root')
);
Any questions, let me know.
I have updated your code. Please have a look below:
class WalkInBook extends Component {
constructor(props)
{
super(props);
this.state={
firstName:'',
lastName:'',
phone:'',
email:'',
course:'',
};
}
handleClick = () => {
console.log(this.state);
}
handleChangeText = (event) => {
const { target:{ value, name } } = event
this.setState({ [name]:value });
}
render() {
const { classes } = this.props;
return (
<div align="center">
<Typography>
<div>
<div className={classes.root} noValidate autoComplete="off">
<TextField onChangeText={(e) => this.handleChangeText(e)} id="standard-basic" name="firstName" label="First Name" />
</div>
<div className={classes.root} noValidate autoComplete="off">
<h1>{this.state.data}</h1>
<TextField onChangeText={(e) => this.handleChangeText(e)} id="standard-basic" name="lastName" label="Last Name" />
</div>
<div className={classes.root} noValidate autoComplete="off">
<TextField onChangeText={(e) => this.handleChangeText(e)} id="standard-basic" name="phone" label="Phone" />
</div>
<div className={classes.root} noValidate autoComplete="off">
<TextField onChangeText={(e) => this.handleChangeText(e)} id="standard-basic" name="email" label="Email" />
</div>
<div className={classes.root} noValidate autoComplete="off">
<TextField onChangeText={(e) => this.handleChangeText(e)} id="standard-basic" name="course" label="Course" />
</div>
</div>
<div className={classes.root} noValidate autoComplete="off">
<Button type="submit" onClick={this.handleClick} variant="outlined">Submit</Button>
</div>
</Typography>
</div>
);
}
}
I hope it would help you out.

Netlify form dashboard doesn't display input type file

I'm building a simple website with Gatsby. The website has a form which contains some input fields type text and one input type file.
I'm using styled-component.
const initialState = {
firstName: "",
lastName: "",
email: "",
phoneNumber: "",
message: "",
cv: null,
linkedinUrl: "",
isSent: false,
validation: validator.valid(),
}
const [formData, setFormData] = useState({
...initialState,
})
const [isFormSubmitted, setIsFormSubmitted] = useState(false)
const handleInputChange = event => {
setFormData({
...formData,
[event.target.name]: event.target.value,
})
}
const handleFileLoad = e => {
setFormData({
...formData,
cv: e.target.files[0],
})
}
const handleSubmit = event => {
event.preventDefault()
// const { firstName, lastName, email, phoneNumber, siteWeb, message } = formData
const validation = validator.validate(formData)
setFormData({
...formData,
validation,
})
setIsFormSubmitted(true)
if (validation.isValid) {
const encode = data => {
console.log(data)
return Object.keys(data)
.map(
key => encodeURIComponent(key) + "=" + encodeURIComponent(data[key])
)
.join("&")
}
fetch(event.target.action, {
method: "POST",
headers: { "Content-Type": "multipart/form-data" },
body: encode({ "form-name": title, job, ...formData }),
})
.then(() => setFormData({ ...initialState, isSent: true }))
.catch(error => alert(error))
}
}
const {
firstName,
lastName,
email,
phoneNumber,
linkedinUrl,
message,
validation,
} = formData
// if the form has been submitted at least once, then check validity every time we render
// otherwise just use what's in state
const copyData = { ...formData }
const formValidation =
isFormSubmitted && !formData.isSent
? validator.validate(copyData)
: validation
return (
<FormStyled
onSubmit={handleSubmit}
data-netlify="true"
name={title}
method="POST"
netlify-honeypot="bot-field"
>
<Spacer flex="1 1 50%">
<Input
type="text"
placeholder="Prénom"
value={firstName}
handleChange={e => handleInputChange(e)}
name="firstName"
required
fullWidth
id="firstName"
/>
<input type="hidden" name="form-name" value={title} />
<input
type="text"
value={job}
name="job"
id="job"
style={{ display: "none" }}
/>
<ValidationMessage isInvalid={formValidation.firstName.isInvalid}>
{formValidation.firstName.message}
</ValidationMessage>
</Spacer>
<Spacer flex="1 1 50%">
<Input
type="text"
placeholder="Nom"
value={lastName}
handleChange={e => handleInputChange(e)}
name="lastName"
required
fullWidth
id="lastName"
/>
<ValidationMessage isInvalid={formValidation.lastName.isInvalid}>
{formValidation.lastName.message}
</ValidationMessage>
</Spacer>
<Spacer flex="1 1 50%">
<Input
type="tel"
placeholder="Téléphone"
value={phoneNumber}
handleChange={e => handleInputChange(e)}
name="phoneNumber"
fullWidth
id="phoneNumber"
/>
<ValidationMessage isInvalid={formValidation.phoneNumber.isInvalid}>
{formValidation.phoneNumber.message}
</ValidationMessage>
</Spacer>
<Spacer flex="1 1 50%">
<Input
type="email"
placeholder="E-mail"
value={email}
handleChange={e => handleInputChange(e)}
name="email"
required
fullWidth
id="email"
/>
<ValidationMessage isInvalid={formValidation.email.isInvalid}>
{formValidation.email.message}
</ValidationMessage>
</Spacer>
<Spacer flex="1 1 auto">
<Button title="Télécharger votre CV" colors="primary">
<InputFile type="file" id="cv" onChange={handleFileLoad} name="cv" />
</Button>
</Spacer>
<Spacer flex="1 1 auto">
<Text>et / ou</Text>
</Spacer>
<Spacer className="linkedin-url">
<Input
type="url"
placeholder="Lien de votre profil linkedin"
value={linkedinUrl}
handleChange={e => handleInputChange(e)}
name="linkedinUrl"
required
fullWidth
id="linkedinUrl"
iconLeft={
<LogoLinkedin>
<img src={Lkd} alt="lien Linkedin" />
</LogoLinkedin>
}
></Input>
</Spacer>
<Spacer>
<Textarea
type="text"
placeholder="Votre message..."
value={message}
handleChange={e => handleInputChange(e)}
name="message"
required
fullWidth
id="message"
/>
<ValidationMessage isInvalid={formValidation.message.isInvalid}>
{formValidation.message.message}
</ValidationMessage>
</Spacer>
<SuccessMessage isSent={formData.isSent}>
Merci, votre message a bien été envoyé !
</SuccessMessage>
<Spacer textAlign="center">
<Button title="Envoyer" type="submit" colors="primary" />
</Spacer>
</FormStyled>
)
}
Below is the request payload when I send the file :
form-name=postuler&job=Tous&firstName=foo&lastName=bar&email=foo.bar%40gmail.com&phoneNumber=0102030405&message=foo%20bar%20baz&cv=%5Bobject%20File%5D&linkedinUrl=https%3A%2F%2Fwww.foobar.fr&isSent=false&validation=%5Bobject%20Object%5D&ignore_whitespace=false&allow_display_name=false&require_display_name=false&allow_utf8_local_part=true&require_tld=true
When I send the form, data are correctly displayed in Netlify form dashboard except the content of the input type file which remains empty. I want the content of the input type file to be displayed in Netlify dashboard (Regarding the doc, I assume it should be a link to access the file).
From what I understand looking carefully at the request payload, I'm sending cv=%5Bobject%20File, so I guess this the problem, because Netlify could not be able to retrieve the real content of the cv input.

Categories

Resources