How to update state with input values - javascript

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
}

Related

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} />

Form validation react

i want to validate my form by checking if all the fields are filled. I am quite new to react. Any suggestions? I have got the states ready, but i am pretty much stuck. Thank you in advance for your replies. I appreciate it
my code:
const [fields, setFields] = useState({
name: '',
email: '',
subject: '',
msg: '',
});
const handleSubmit = (event) => {
emailjs.sendForm().then(
(result) => {
console.log(result.text);
},
(error) => {
console.log(error.text);
}
);
alert('form submitted');
event.target.reset();
event.preventDefault();
};
<form onSubmit={handleSubmit}>
<div className={styles.firstInputs}>
<div>
<label>name</label>
<br />
<input
type='text'
refs='name'
name='name'
placeholder='your name'
></input>
</div>
<div>
<label>email</label>
<br />
<input type='email' name='email' placeholder='email'></input>
</div>
</div>
<label>subject</label>
<br />
<input
type='text'
name='subject'
placeholder='subject'
className={styles.subject}
></input>{' '}
<br />
<label>message</label> <br />
<textarea placeholder='your message' name='message'></textarea>
<br />
<button type='submit' className={styles.sendForm}>
SUBMIT
</button>
</form>;
You are not using your state correctly there.
Set the values of the fields to what is in the state, then change the state when the fields change.
Don't forget you can just add the required attribute to your HTML element to make sure it gets some kind of value.
Then you just validate the state before submission.
Don't just fall back on packages all the time as people suggest here. As you say, you are new to React so, learn to set things up manually (which is basically less work for small forms). Once you understand that, then consider if having another dependency is really saving you time.
See sample code below in action here: https://codesandbox.io/s/form-validation-pbbf1
import { useState } from "react";
import "./styles.css";
const defaultFields = { name: "", email: "", subject: "", message: "" };
export default function App() {
const [fields, setFields] = useState(defaultFields);
const handleSubmit = (event) => {
// Stop form from resetting
event.preventDefault();
// Check fields
if (fields.name.length < 2) {
return alert("Name should be greater than 1 character.");
}
// etc...
// Send off data
/*
emailjs.sendForm().then(
(result) => {
console.log(result.text);
},
(error) => {
console.log(error.text);
}
);
*/
// I would probably put these two
// lines inside the then block above.
setFields(defaultFields);
alert("form submitted");
};
const handleFieldChange = (e) => {
const { name, value } = e.target;
setFields((previousFields) => ({ ...previousFields, [name]: value }));
};
return (
<form onSubmit={handleSubmit}>
{/* NAME */}
<div>
<label>name</label>
<br />
<input
type="text"
name="name"
placeholder="your name"
value={fields.name}
required
onChange={handleFieldChange}
></input>
</div>
{/* EMAIL */}
<div>
<label>email</label>
<br />
<input
type="email"
name="email"
placeholder="email"
value={fields.email}
required
onChange={handleFieldChange}
></input>
</div>
{/* SUBJECT */}
<div>
<label>subject</label>
<br />
<input
type="text"
name="subject"
placeholder="subject"
value={fields.subject}
required
onChange={handleFieldChange}
></input>{" "}
<br />
</div>
{/* MESSAGE */}
<div>
<label>message</label> <br />
<textarea
placeholder="your message"
name="message"
value={fields.message}
required
onChange={handleFieldChange}
></textarea>
</div>
<button type="submit">SUBMIT</button>
</form>
);
}

Get values from form with React and Axios

** 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.

Cannot read property 'value' of null in ReactJS

I've been trying to console.log these 2 inputs, but can't seem to figure it out, can anyone tell me what I've done wrong?
I keep getting the Cannot read property 'value' of null error
function printInputs() {
let username = document.getElementById('user').value
let password = document.getElementById('pass').value
console.log(username);
console.log(password);
}
function App() {
return (
<div className="App">
<h1>Log In</h1>
<h1>{code}</h1>
<form>
<input className='userInput' id='user' type='text' placeholder='username' /><br />
<input className='userInput' id='pass' type='password' placeholder='password' /><br />
<input className='userSubmit' type='submit' value='Log In' onSubmit={printInputs()} />
</form>
</div>
);
}
onSubmit={printInputs()}
You are trying to call printInputs immediately (before the render function has returned anything so before the inputs are in the page).
You need to pass a function to onSubmit:
onSubmit={printInputs}
That said, this is not the approach to take for getting data from forms in React. See the Forms section of the React guide for the right approach.
The way to write forms in react. Working example demo
function App() {
const [state, setState] = React.useState({ username: "", password: "" });
const handleSubmit = e => {
e.preventDefault();
console.log(state);
};
const handleChange = e => {
setState({
...state,
[e.target.name]: e.target.value
});
};
return (
<div className="App">
<h1>Log In</h1>
<form onSubmit={handleSubmit}>
<input
className="userInput"
name="username"
type="text"
placeholder="username"
onChange={handleChange}
/>
<br />
<input
className="userInput"
name="password"
type="password"
placeholder="password"
onChange={handleChange}
/>
<br />
<input className="userSubmit" type="submit" value="Log In" />
</form>
</div>
);
}
in the first never use real dom to manipulate the dom in
React ,use a state to get de value and the onSumbit is used in Form tag
import React, { useState } from "React";
const App = () => {
const [userName, setUserName] = useState("");
const [password, setPassword] = useState("");
const printInputs = () => {
console.log(userName);
console.log(password);
};
return (
<div className="App">
<h1>Log In</h1>
<form onSubmit={printInputs}>
<input
className="userInput"
id="user"
type="text"
placeholder="username"
onChange={event => setUserName(event.target.value)}
/>
<br />
<input
className="userInput"
id="pass"
type="password"
placeholder="password"
onChange={event => setPassword(event.target.value)}
/>
<br />
<input
className="userSubmit"
type="submit"
value="Log In"/>
</form>
</div>
);
};
export default App;

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