I have a form where I want to know if the input values are empty when onSubmit, they are not sent. I have tried to do it through the if of handleInputChange but this isn't working:
const handleInputChange = (e: React.FormEvent<HTMLInputElement>) => {
if ((e.target as HTMLInputElement).value) {
setNewPost({
...newPost,
[(e.target as HTMLInputElement).name]: (e.target as HTMLInputElement).value
})
}
e.preventDefault();
};
All the code:
const New: React.FC = () => {
// const [newPost, setNewPost] = useState("");
const [newPost, setNewPost] = useState({
title: '',
author: '',
content: ''
})
const handleInputChange = (e: React.FormEvent<HTMLInputElement>) => {
if ((e.target as HTMLInputElement).value) {
setNewPost({
...newPost,
[(e.target as HTMLInputElement).name]: (e.target as HTMLInputElement).value
})
}
e.preventDefault();
};
const createPost = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault(); //Detiene el formulario para que no actualize la página
setPost(newPost)
}
return (
<div className="containerHomepage">
<form className="formulari" onSubmit={createPost}>
<div className="containerBreadCrumb">
<ul className="breadCrumb">
<li>Posts</li>
</ul>
</div>
<div className="containerTitleButton">
<input
className=""
type="text"
placeholder='Post title'
name="title"
onChange={handleInputChange}
></input>
<button
className="button"
type="submit"
>Save</button>
</div>
<div className="containerEdit">
<input
className=""
type="text"
placeholder='Author'
name="author"
onChange={handleInputChange}
></input>
<input
className=""
type="text"
placeholder='Content'
name="content"
onChange={handleInputChange}
></input>
</div>
</form>
</div>
);
};
// ========================================
export default New;
Your current handleInputChange makes it so that the user cannot change any input to an empty string. There's a major usability flaw here. Once the user types the first character, they cannot delete it! You should allow the inputs to be empty, but disallow submitting the form unless all fields are filled out.
You can use e.currentTarget instead of e.target to avoid a lot of type assertions. There is more information in this question, but what's important here is that e.currentTarget will always be the HTMLInputElement.
const handleInputChange = (e: React.FormEvent<HTMLInputElement>) => {
setNewPost({
...newPost,
[e.currentTarget.name]: e.currentTarget.value
});
};
#rax's answer is on the right track, but I'm going to go further down that path.
An any point in time, you can know whether the form is valid or not by looking at the current state of newPost. There are lots of ways to write this, which all do the same thing:
const isValid = Boolean(newPost.title && newPost.author && newPost.content);
Using type coercion. All strings are truthy except for the empty string.
const isValid = newPost.title !== '' && newPost.author !== '' && newPost.content !== '';
From #Vladimir Trotsenko's answer.
const isValid = Object.values(newPost).every(value => value.length > 0)
Looping over all values of newPost so you don't need to change anything if you add an extra field.
You can use this isValid variable to conditionally disable the "Save" button.
<button type="submit" disabled={!isValid}>Save</button>
You can also use isValid to show messages or other visible feedback to the user. For example, you can show a message when hovering over the disabled button which tells them why it has been disabled.
<button
type="submit"
disabled={!isValid}
title={isValid ? "Create your post" : "All fields must be filled out."}
>
Save
</button>
I'm checking if (isValid) in the createPost function to be on the safe side, but I believe that this is not actually necessary as the form won't be submitted (even when hitting Enter) if the submit button is disabled.
const createPost = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault(); // stop the form from reloading the page.
if (isValid) {
// put your actual code here instead.
alert("submit success");
}
};
Complete code:
import React, { useState } from "react";
const New: React.FC = () => {
const initialState = {
title: "",
author: "",
content: ""
};
const [newPost, setNewPost] = useState(initialState);
const isValid = Boolean(newPost.title && newPost.author && newPost.content);
const handleInputChange = (e: React.FormEvent<HTMLInputElement>) => {
setNewPost({
...newPost,
[e.currentTarget.name]: e.currentTarget.value
});
};
const createPost = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault(); //stop the form from reloading the page
if (isValid) {
alert("submit success");
}
};
return (
<div className="containerHomepage">
<form className="formulari" onSubmit={createPost}>
<div className="containerBreadCrumb">
<ul className="breadCrumb">
<li>Posts</li>
</ul>
</div>
<div className="containerTitleButton">
<input
className=""
type="text"
placeholder="Post title"
name="title"
onChange={handleInputChange}
value={newPost.title}
/>
<button
className="button"
type="submit"
disabled={!isValid}
title={
isValid ? "Create your post" : "All fields must be filled out."
}
>
Save
</button>
</div>
<div className="containerEdit">
<input
className=""
type="text"
placeholder="Author"
name="author"
onChange={handleInputChange}
value={newPost.author}
/>
<input
className=""
type="text"
placeholder="Content"
name="content"
onChange={handleInputChange}
value={newPost.content}
/>
</div>
</form>
</div>
);
};
export default New;
CodeSandbox
You can compare your input value to empty string like that :
inputValue === ''
or the size of the string :
inputValue.length === 0
And check the value in if statement with inside your submit.
You can validate the empty field inside createPost which should look something like:
const createPost = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault(); //stop the form from reloading the page
if (!newPost.title || !newPost.author || !newPost.content) {
//show some error message
} else {
//perform further action
setPost(newPost);
}
}
For a full working example click here.
When you try to submit, firstly, you need to check whether input values are present. In order to do that you check each input value to equal empty string.
For a better visualization, create variable that would be responsible for that:
const isValid = newPost.title !== '' && newPost.author !== '' && newPost.content !== ''
Now, if isValid is true, we submit the form, if not, we do not.
const createPost = (e) => {
e.preventDefault()
if (isValid) {
// make api request
} else {
// handle empty fields
}
}
Related
I have started an internship I have to build a to-do list using NEXT JS. but the problem arises that the app also updates an empty string. I have to work on this and have more than 20 hours to dig up a solution. I wasn't able to solve it. I tried passing some parameters but it's not working.
import { useState } from "react"
import '../styles/globals.css'
const index=()=> {
const [userinput,setuserinput]=useState("")
const [todolist,settodolist]=useState([])
const handlechange=(e)=>{
e.preventDefault()
if(e.target.value!=""){
setuserinput(e.target.value)
}
}
const handlesubmit=(e)=> {
settodolist([
userinput,
...todolist
])
e.preventDefault()
}
const handledelete=(todo)=>{
const updatedelete=todolist.filter(todoitem => todolist.indexOf(todoitem) != todolist.indexOf(todo))
settodolist(updatedelete)
}
return(
<div className="FLEX">
<h3 className="heading">Welcome to Next JS To Do app</h3>
<form className="FORM">
<div className="Wrap">
<input type="text" onChange={handlechange} placeholder="Enter a todo item" className="INPUT"></input>
<button onClick={handlesubmit} className="Button">Submit</button>
</div>
</form>
<ul>
{
todolist.length>=1?todolist.map((todo,idx)=>{
return <li key={idx}>{todo} <button onClick={(e)=>{
e.preventDefault()
handledelete(todo)
}}>Delete</button></li>
}):"Enter a Todo List"
}
</ul>
</div>
)
}
export default index
You need to pass the value prop to your input element:
<input type="text" value={userinput} onChange={handlechange} placeholder="Enter a todo item" className="INPUT"></input>
If you don't want the user to submit an empty item to the todo list, check if the userinput is empty or not.
const handlesubmit = (e) => {
if (userinput === "") return
settodolist([
userinput,
...todolist
])
e.preventDefault()
}
I believe the question is asking to prevent the user from entering a todo item with no name. In this case, do as the previous comment mentioned and add the value prop to the input:
<input type="text" value={userinput} onChange={handlechange} placeholder="Enter a todo item" className="INPUT"></input>
then add this to your handleSubmit function:
const handlesubmit = (e) => {
e.preventDefault();
if (userinput != '') {
settodolist([userinput, ...todolist]);
}
};
This question already has answers here:
How to maintain state after a page refresh in React.js?
(8 answers)
Closed 12 months ago.
I have created a basic form validation page using ReactJS with input fields of validation using regex.
I have a problem that when I fill the input fields with some data and before completing it if I click refresh the page the input fields are getting cleared.
I want to stop the input fields from clearing after refresh.
How can I do that.
Below is my code:
import React, { useState, useEffect } from 'react';
import PhoneIcon from '#mui/icons-material/Phone';
import LockIcon from '#mui/icons-material/Lock';
import { NavLink, useNavigate } from 'react-router-dom';
import "../index.css";
function Github () {
const initialvalues = {number:"", password:""}
const [formValues, setFormValues] = useState(initialvalues);
const [formErrors, setFormErrors] = useState({});
const [isSubmit, setIsSubmit] = useState(false);
const handleChange = (e) =>{
const{name,value} = e.target;
setFormValues({...formValues, [name]:value});
}
const handleSubmit = (e) =>{
e.preventDefault();
const errors = validate(formValues);
if (Object.keys(errors).length) {
setFormErrors(errors);
} else {
setIsSubmit(true);
}
}
let navigate = useNavigate();
const handleSubmits = (e) =>{
e.preventDefault();
const passerrors = validates(formValues);
if (Object.keys(passerrors).length) {
setFormErrors(passerrors);
} else {
navigate('/admin');
}
}
useEffect(()=>{
console.log(formErrors);
if(Object.keys(formErrors).length ===0 && !isSubmit){
console.log(formValues);
}
},[formErrors])
const validates = (values) =>{
const passerrors ={}
const regexp = /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!##$%^&*_=+-]).{4,12}$/;
if(!values.password){
passerrors.password = "Password is required";
}else if(!regexp.test(values.password)){
passerrors.password = "passsword must contain atleast one uppercase,lowercase,number,special character";
}
else if(values.password.length < 4){
passerrors.password = "Password must me more than 4 characters";
}else if (values.password.length > 6){
passerrors.password = "Password cannot be more than 6 characters";
}
return passerrors;
}
const validate = (values) =>{
const errors = {}
const regexn = /^(\+91[-\s]?)?[0]?(91)?[789]\d{9}$/;
if(!values.number){
errors.number = "Mobile Number is required";
}else if(!regexn.test(values.number)){
errors.number = "Please enter a valid mobile number"
}else if(values.number.length > 10){
errors.number = "number must be only 10 digits"
}
return errors;
};
return (
<div className="container"
style={{textAlign:'center',paddingTop:"50px"}}>
<img src="images/img1.jpg" alt=''
width="100px" height="100px"
style={{borderRadius:"50%"}} /><br/>
<div style={{justifyContent:'space-between'}}>
<br/><br/><br/><br/>
{ !isSubmit
?
<form onSubmit={handleSubmit} >
<div>
<div>
<label style={{position:"relative", top:"8px",right:"5px",left:"115px"}}>
<PhoneIcon/></label>
<input className='input_field' type="number" name="number" placeholder='enter number'
autoComplete='off'
value={formValues.number}
onChange={handleChange}
style={{width:"180px",height:"35px"}}
/>
<label className='input_label'>Mobile Number</label>
<p style={{color:"red",fontSize:"13px"}} >{formErrors.number}</p>
</div>
<button className='btn-primary'
style={{width:"210px",height:"30px",fontSize:"15px",
marginLeft:"30px",marginTop:"20px",
backgroundColor:" rgb(0, 110, 255)"
}}>
Submit</button>
</div>
</form>
:
<form onSubmit={handleSubmits} >
<div>
<div>
<label style={{position:"relative", top:"8px",right:"5px",left:"80px"}} ><LockIcon/></label>
<input className='input_fieldp' type="password" name='password' placeholder='enter password'
value={formValues.password}
onChange={handleChange}
style={{width:"180px",height:"35px"}}
/>
<label className='input_labelp'>Password</label>
<p style={{color:"red",fontSize:"13px"}}>{formErrors.password}</p>
</div>
<button
style={{width:"210px",height:"30px",fontSize:"15px",
marginLeft:"30px",marginTop:"20px",
backgroundColor:" rgb(0, 110, 255)"
}}>
Login</button>
</div>
</form>
}
</div>
</div>
)
}
export default Github;
Suggest me how can I do that.
When you refresh you cannot use react state or redux store as they are cleared and initialized with each page refresh. The best approach I see here is to use your localstorage to store the values.
Then you can check whether the data is available in localstorage and use that on the initial render using a useEffect hook.
What you can do is use localstorage. You can use the native localstorage but i do recommend using lscache as it is more flexible (also handles if the browser doesn't have lscace) and since you're using a framework anyway.
what you can do is on your handleCange everytime you save something on state, you also save it on localstorage:
const handleChange = (e) =>{
const{name,value} = e.target;
setFormValues({...formValues, [name]:value});
// you can add a third parameter for expiration if you don't want it to be there forever
lscache.set(name, value);
}
then have a useEffect to handle the fetching of data on the cache on refresh
useEffect(() => {
const number = lscache.get("number");
setFormValues({...formValues, number});
}, [])
PS. Make sure the name of the cache is unique on the form/site.
I have a form with 3 input filed FIRST NAME, LAST NAME, NUMBER. So once forms open there is a particular set of pre filled values coming from backend. So, if i try to add validation check for my firstname and if user makes the filed blank and click submit it shows me undefined in console for the respective firstname value. So, could someone help to add validation check for firstname, last name and number ??
const EditContact = inject('Contacts')(observer((props) => {
const { text, Contactfirst, apptContacts } = props;
const { updateContact } = apptContacts;
const CMS = text.appointmentManager.editAppointmentContact;
const [state, setState] = React.useState({
data: {
firstName: Contactfirst[0],
lastName: Contactfirst[1],
number: Contactfirst[2],
},
firstNameValid: '',
lastNameValid: '',
numberValid: '',
});
const handleTextareaChange = (event) => {
const { data } = state;
data[event.target.name] = event.target.value;
setState({
data,
});
};
const valid = () => {
if (state.data.firstName !== 'undefined') {
setState({ firstNameValid: 'Required.Please enter your given name.' });
}
};
const saveButton = () => {
if (valid()) {
const personName = `${state.data.firstName} ${state.data.lastName}`;
const primaryContact = {
name: personName,
phoneNumber: state.data.number,
};
}
};
return (
<div>
<VerticalSpacing size={ABLE_SPACING_SIZE.spacing4x} />
<h1 tabIndex="-1" className="HeadingB mt-sheet-heading">
{CMS.heading1}
</h1>
<VerticalSpacing size={ABLE_SPACING_SIZE.spacing3x} />
<TextField id="givenName" name="firstName" label={CMS.name} onChange={handleTextareaChange} value={(state.data.firstName !== 'undefined') ? state.data.firstName : ''} />
<p>{state.firstNameValid}</p>
<VerticalSpacing size={ABLE_SPACING_SIZE.spacing3x} />
<TextField id="familyName" name="lastName" label={CMS.familyName} onChange={handleTextareaChange} value={(state.data.lastName !== 'undefined') ? state.data.lastName : ''} />
<p>{state.lastNameValid}</p>
<VerticalSpacing size={ABLE_SPACING_SIZE.spacing3x} />
<TextField id="mobileNumber" name="number" label={CMS.mobile} onChange={handleTextareaChange} value={(state.data.number !== 'undefined') ? state.data.number : ''} />
<p>{state.numberValid}</p>
<VerticalSpacing size={ABLE_SPACING_SIZE.spacing4x} />
<ActionButton className={styles.saveCta} variant="HighEmphasis" label={CMS.saveCTA} onClick={() => saveButton()} />
</div>
);
}));
export default EditContact ;
Handling form state and validation is a problem many of us have faced. If you are having trouble solving the issue on your own I would suggest taking look at a library that handles the heavy lifting for you. One such library is Formik https://formik.org/docs/overview
Here is a minimal example that illustrates it in action:
https://codesandbox.io/s/zkrk5yldz
If you want to use material ui for your components that is easy to apply validation to your text fields.
Just follow this link
https://mui.com/components/text-fields/#validation
Halo guys I am quite new to react and I want to submit a form with only a text area with enter key press. I followed some of the SO questions but still no luck as it is not getting submitted. I also want to clear the text area after the submit. How can I do it with the below code?
This is the code I currently have.
const { register, handleSubmit, control, errors } = useForm();
const CommentOnSubmit = (data) => {
let formData = new FormData();
formData.append('content', data.content);
formData.append('user', user?.id);
axiosInstance.post(`api/blogs/` + slug + `/comment/`, formData);
} ;
// const commentEnterSubmit = (e) => {
// if(e.key === 'Enter' && e.shiftKey == false) {
// return(
// e.preventDefault(),
// CommentOnSubmit()
// )
// }
// }
<form noValidate onSubmit={handleSubmit(CommentOnSubmit)}>
<div className="post_comment_input">
<textarea
type="text"
placeholder="Write a comment..."
name="content"
ref={register({required: true, maxLength: 1000})}
/>
</div>
<div className="comment_post_button">
<Button type="submit" variant="contained" color="primary">comment</Button>
</div>
</form>
Please do help.
Thanks a lot.
you can use React SyntheticEvent onKeyPress like this:
<textarea
type="text"
placeholder="Write a comment..."
onKeyPress={ commentEnterSubmit}
name="content"
ref={register({ required: true, maxLength: 1000 })}
/>
UPDATE
In your commentEnterSubmit function:
const commentEnterSubmit = (e) => {
if (e.key === "Enter" && e.shiftKey == false) {
const data = {content:e.target.value};
return handleSubmit(CommentOnSubmit(data));
}
And if you want to reset your input you can use the setValue from useForm hooks.
like this:
add setValue to const { register, handleSubmit, control, errors,setValue } = useForm();
const CommentOnSubmit = (data) => {
let formData = new FormData();
formData.append("content", data);
formData.append("user", user?.id);
// your axios call ...
setValue("content","");
};
I have made a code sandBox based on your example
This seems like a simple thing to do but after much fiddling, I can't figure out what's wrong. I'm a noob to React so forgive me.
I have a form for logging in. Like most login forms, it's asking for a username and password. Then it has a button to submit. My understanding is that a component will re-render if the state is changed. I have onchange events on each input field that updates the state. So if the field is empty, I press the button to submit, I would expect that the error will show. If I fill in a field, I would expect the error message to go away because the state changed. Am I misunderstanding?
Here is my event handler:
handleLogin(event) {
event.preventDefault();
if (this.state.username == '') {
this.setState({usernameError: "Need to enter a username"})
return;
}
if (this.state.password == '') {
this.setState({passwordError: "Need to enter a password"})
return;
}
}
And the form:
render() {
return(
<form className="login-form">
<h1 className="login-form__header"><FontAwesomeIcon icon="key" className="registration-form__icon"/><i className="fal fa-route-highway"></i>Log Into Your Account</h1>
<input type="text" name="username" placeholder="Username" className="login-form__input" onChange={(event,newValue) => this.setState({username:newValue})}/>
{this.state.usernameError &&
<p class="login-form__error"><FontAwesomeIcon icon="times-circle"/> {this.state.usernameError}</p>
}
<input type="password" name="password" placeholder="Password" className="login-form__input" onChange={(event,newValue) => this.setState({password:newValue})}/>
{this.state.passwordError &&
<p class="login-form__error"><FontAwesomeIcon icon="times-circle"/> {this.state.passwordError}</p>
}
<button className="login-form__button" onClick={this.handleLogin}>Log Into Your Account</button>
</form>
);
}
Right, but you never configured any logic to clear the errors if the field is not empty. Currently, there isnt any logic set-up to turn usernameError and passwordError back to an empty-string or null value.
You might be under the impression that the state is cleared when you re-render but that is not the case. The state-object prior to the re-render still persists, only changing the key-value pair(s) you last updated within this.setState().
Try this:
handleLogin(event) {
event.preventDefault();
const { username, password } = this.state
this.setState({
...this.state,
usernameError: username.length > 0 ? "" : "Need to enter a username",
passwordError: password.length > 0 ? "" : "Need to enter a password"
})
}
Here's a working sandbox with a sligtly modified version of your code. (I removed the FontAwesomeIcons). https://codesandbox.io/s/cool-meninsky-y9r4y
First of all, onChange={(event,newValue) => this.setState({username:newValue})} this is not a good approach, as it will create a new function on every render. So I would suggest to create a dedicated function like -
handleInputChange(event) {
const target = event.target;
const value = target.value;
const name = target.name;
// Make sure the name is as per with your html username password and update the state accordingly
this.setState({
[name]: value
});
}
Do remember to reset the usernameError and passwordError properties of your state on each related onChange event. Otherwise the error message will persist on HTML.
Hi you can try the below code
function validate(email, username, password) {
// true means invalid, so our conditions got reversed
return {
username: username.length === 0, //true if username is empty
password: password.length === 0, //true if password is empty
};
}
class LoginForm extends React.Component {
constructor() {
super();
this.state = {
username: '',
password: '',
touched: {
username: false,
password: false,
},
};
}
handleUsernameChange = (evt) => {
this.setState({ username: evt.target.value });
}
handlePasswordChange = (evt) => {
this.setState({ password: evt.target.value });
}
handleBlur = (field) => (evt) => {
this.setState({
touched: { ...this.state.touched, [field]: true },
});
}
handleSubmit = (evt) => {
if (!this.canBeSubmitted()) {
evt.preventDefault();
return;
}
const { username, password } = this.state;
alert(`Logined: ${email} password: ${password}`);
}
canBeSubmitted() {
const errors = validate(this.state.username, this.state.password);
const isDisabled = Object.keys(errors).some(x => errors[x]);
return !isDisabled;
}
render() {
const errors = validate(this.state.username, this.state.password);
const isDisabled = Object.keys(errors).some(x => errors[x]);
const shouldMarkError = (field) => {
const hasError = errors[field];
const shouldShow = this.state.touched[field];
return hasError ? shouldShow : false;
};
return (
<form className="login-form" onSubmit={this.handleSubmit}>
<h1 className="login-form__header">
<FontAwesomeIcon icon="key" className="registration-form__icon"/>
<i className="fal fa-route-highway"></i>Log Into Your Account
</h1>
<input
className={shouldMarkError('username') ? "error" : ""}
type="text" name="username" placeholder="Username"
value={this.state.username}
onBlur={this.handleBlur('username')
onChange={this.handleUsernameChange} />
<p className={shouldMarkError('username') ? "error" : "hidden"}>
<FontAwesomeIcon icon="times-circle"/> Need to enter a username
</p>
<input type="password" name="password" placeholder="Password"
className={shouldMarkError('password') ? "error" : ""}
value={this.state.password}
onChange={this.handlePasswordChange}
onBlur={this.handleBlur('password')} />
<p className={shouldMarkError('password') ? "error" : "hidden"}>
<FontAwesomeIcon icon="times-circle"/> Need to enter a password
</p>
<button disabled={isDisabled} className="login-form__button"
onClick={this.handleLogin}>Log Into Your Account</button>
</form>
)
}
}
Hope the code could helpful for you.
You can also refer the Demo Validation for Signup
As mentioned by #Satyaki onChange={(event,newValue) => this.setState({username:newValue})} is not a good option you should define separate method for this, alternatively you can change your code to as follows:
onChange={(event,newValue) => this.setState({username:newValue})}, () => {})
This will make sure to complete the lifecycle of setState.