React how to validate form before making postmutation - javascript

I have a react form to add some data to my database. I'm using Prisma and Graphql. I nested the mutations query to a button. so when the button is clicked the form is submitted but I'm wondering how I can first validate if all the field are filled in before submitting them?
Code:
render() {
const {id, firstname, lastname} = this.state
const UPDATE_MUTATION = gql`
mutation UpdateMutation($id:ID!, $firstname: String!, $lastname: String!) {
updateClient(id:$id, firstname: $firstname, lastname: $lastname) {
id
firstname
lastname
}
}
`
return (
<React.Fragment>
{
<Modal
{...this.props}
size="lg"
aria-labelledby="contained-modal-create-service"
centered
>
<Modal.Header closeButton >
<Modal.Title id="contained-modal-title-vcenter">Update service</Modal.Title>
</Modal.Header>
<Modal.Body>
<div className="flex flex-column mt3 client-row ">
<section className="form-group firstname">
<label>Firstname:</label>
<input
className="form-control "
value={firstname}
onChange={e => this.setState({ firstname: e.target.value })}
type="text"
placeholder="A name for the service"
/>
</section>
<section className="form-group lastname">
<label>Lastname:</label>
<input
className="form-control "
value={lastname}
onChange={e => this.setState({ lastname: e.target.value })}
type="text"
placeholder="The service cost"
/>
</section>
</div>
</Modal.Body>
<Modal.Footer>
<Mutation mutation={UPDATE_MUTATION}
variables={{id, firstname, lastname}}>
{/* onCompleted={() => this.props.history.push('/')} */}
{updateMutation =>
<button onClick={() => {updateMutation(); this.props.onHide() ; window.location.reload(false)} } className="btn submit">Update</button>
}
</Mutation>
</Modal.Footer>
</Modal>
}
</React.Fragment>

this a simple example :
const form = ()=>{
const [form,setForm] = useState({userName:"",password:""})
const [error,setError] = useState(false)
const validateForm = ()=>{
if(form.userName.length===0 && form.password.length===0)
return false
return true
}
const handleSubmit = ()=>{
if(validateForm()){
// do your stuff
}
else{
setError(true)
}
}
const handleChange =(e)=>{
if(error) setError(false);
const {target} = e
setForm(current=>({...current,[target.name]:target.value}))
}
return (
<form onSubmit={handleSubmit}>
<input type="text" name="userName" value={form.userName} onChange={handleChange}/>
<input type="password" name="password" value={form.password} onChange={handleChange}/>
<button type="submit">login</button>
{error && <p> UserName and password are required!<p>
</form>
)
}
this is it but you can save a lot of work by using react form library like formik with yup validation library

Related

how to add validation to a reactjs form

I have developed a registration form and I tried using validation format but it is not working. I don't know how and where to code a function for it and apply it. please help me how to do it. I will attach the code i have done till now.
import React, { useState } from 'react';
import { Button, Form } from 'semantic-ui-react'
import axios from 'axios';
import { useNavigate } from 'react-router';
export default function Create() {
let navigate = useNavigate();
const [Employee_name, setEmployee_name] = useState('');
const [Employee_id, setEmployee_id] = useState('');
const [Employee_address, setEmployee_address] = useState('');
const [Employee_post, setEmployee_post] = useState('');
const postData = () => {
axios.post(`http://localhost:5000/qo`, {
Employee_name,
Employee_id,
Employee_address,
Employee_post
}).then(() => {
navigate('/read')
})
alert('Data Saved')
}
return (
<div>
<Form className="create-form">
<Form.Field required={true}>
<label>Employee Name</label>
<input placeholder='Employee Name' onChange={(e) => setEmployee_name(e.target.value)} required={true}/>
</Form.Field>
<Form.Field required={true}>
<label>Employee ID</label>
<input placeholder='Employee ID' onChange={(e) => setEmployee_id(e.target.value)} required={true}/>
</Form.Field>
<Form.Field required={true}>
<label>Employee Address</label>
<input placeholder='Employee Address' onChange={(e) => setEmployee_address(e.target.value)} required={true}/>
</Form.Field>
<Form.Field required={true}>
<label>Employee Position</label>
<input placeholder='Employee Position' onChange={(e) => setEmployee_post(e.target.value)} required={true}/>
</Form.Field>
<Button onClick={postData} type='submit'>Submit</Button>
</Form>
</div>
)
}
There are good libraries out there, that can help you with form validation before allowing a user to submit the form.
One such library could be formik together with Yup.
This is how I do client side form validation on my forms:
Login schema (made with Yup):
import * as Yup from 'yup';
const loginSchema = Yup.object().shape({
username: Yup.string()
.min(3, 'Minimum 3 chars')
.max(50, 'Max 50 chars')
/* password: Yup.string()
.min(6, 'Minimum 6 chars')
.max(50, 'Max 50 chars')
*/
});
Login component:
export const Login = () => {
const [loading, setLoading] = useState(false);
const formik = useFormik({
initialValues: {
username: ''
},
validationSchema: loginSchema,
onSubmit: async (values, {setStatus, setSubmitting}) => {
setLoading(true);
setStatus(null);
try {
// Call your API function to post to the backend here
// You can access your form values in the "values" parameter
setLoading(false);
} catch (error) {
console.error(error);
setStatus('User not found');
setSubmitting(false);
setLoading(false);
}
}
});
}
return (
<form
onSubmit={formik.handleSubmit}
className={'auth-form-wrapper'}
>
{/* begin::Heading */}
<div className={'auth-form-header'}>
<h1>Log in</h1>
<div className={'auth-error-message-container'}>
formik.status && (
<p className={'error-message'}>{formik.status}</p>
)
}
</div>
</div>
{/* end::Heading */}
{/* begin::Form group content */}
<div className={'auth-form-content'}>
{/* begin::Form group */}
<div className={'dynamic-input-container'}>
<input type='text'
id="username"
value={formik.values.username}
onChange={formik.handleChange}
placeholder='Username'
className={'dynamic-input auth-input ' + clsx(
{'is-invalid': formik.touched.username && formik.errors.username},
{
'is-valid': formik.touched.username && !formik.errors.username
}
)}
autoComplete='off'
/>
{formik.touched.username && formik.errors.username && (
<div className='fv-plugins-message-container'>
<span role='alert'>{formik.errors.username}</span>
</div>
)}
</div>
{/* end::Form group*/}
{/* begin::Action */}
<div className='auth-btn-container'>
<Button variant="contained" size="medium" type={'submit'} disabled={loading}>
{
!loading ? <span>Continue</span>
:
(
<span className={'auth-spinner-container'}>
<ClipLoader
loading={loading}
size={20}
aria-label='Loading Spinner'
/>
</span>
)
}
</Button>
</div>
{/* end::Action */}
</div>
{/* end::Form group content */}
</form>
);
Please note, that in my example I only have a "username" input, but you can obviously add as many fields as you wish.
Documentation:
Formik: https://formik.org/docs/tutorial
Yup: https://www.npmjs.com/package/yup
clxs: https://www.npmjs.com/package/clsx
import React, { useState } from 'react';
import { Button, Form } from 'semantic-ui-react'
import axios from 'axios';
import { useNavigate } from 'react-router';
export default function Create() {
let navigate = useNavigate();
const [Employee_name, setEmployee_name] = useState('');
const [Employee_id, setEmployee_id] = useState('');
const [Employee_address, setEmployee_address] = useState('');
const [Employee_post, setEmployee_post] = useState('');
const postData = e => {
e.preventDefault();
if(Employee_name.length == 0) return false;
if(Employee_id.length == 0) return false;
if(Employee_address.length == 0) return false;
if(Employee_post.length == 0) return false;
axios.post(`http://localhost:5000/qo`, {
Employee_name,
Employee_id,
Employee_address,
Employee_post
}).then(() => {
navigate('/read')
})
alert('Data Saved')
}
return (
<div>
<Form className="create-form" onSubmit={e => postData(e)}>
<Form.Field required={true}>
<label>Employee Name</label>
<input placeholder='Employee Name' onChange={(e) => setEmployee_name(e.target.value)} required={true}/>
</Form.Field>
<Form.Field required={true}>
<label>Employee ID</label>
<input placeholder='Employee ID' onChange={(e) => setEmployee_id(e.target.value)} required={true}/>
</Form.Field>
<Form.Field required={true}>
<label>Employee Address</label>
<input placeholder='Employee Address' onChange={(e) => setEmployee_address(e.target.value)} required={true}/>
</Form.Field>
<Form.Field required={true}>
<label>Employee Position</label>
<input placeholder='Employee Position' onChange={(e) => setEmployee_post(e.target.value)} required={true}/>
</Form.Field>
<Button type='submit'>Submit</Button>
</Form>
</div>
)
}
This is updated code from your snippet. try this and let me know what's the progress.
I really appreciate you.

React - All of the states of OnFocus work at the same time

I'm having a problem while constructing signup page.
Specifically, i intended to make the form validation check function when i clicked the each input only.
However, it works all of the inputs together.
Could anyone let me know where to correct in my code?
Summary:
Want to make validation check function. It works seperatly for each input.
Made it, however, when i clicked any one of input, then all of the input's error has activated.
I can't find where it's error, guessing using only one state ? "const [focused, setFocused] = useState(false);"
Additional info, i was able to find the focus function works, however, all of the inputs activated at all togehter... considering wether should i use seperate states for each values? And at the same time, there could be much clean, and neat way...!
Appreciate !
// Signup.css
span {
font-size: 12px;
padding: 3px;
color: red;
display: none;
}
input:invalid[focused="true"] {
border: 1px solid red;
}
input:invalid[focused="true"] ~ span {
display: block;
}
//Signup.js
function(props) {
const navigate = useNavigate();
const [id, setId] = useState("");
const [password, setPassword] = useState("");
const [passwordConfirm, setPasswordConfirm] = useState("");
const [name, setName] = useState("");
const [phone, setPhone] = useState("");
const [email, setEmail] = useState("");
const [focused, setFocused] = useState(false);
const handleFocus = (e) => {
setFocused(true);
};
return (
<>
<div className='full-box'>
<div id='signup-middle-box' className='middle-box'>
<h2>SignUp</h2>
<form onSubmit={SignUpUser}>
<div id='signup-small-box' className='small-box'>
<div className='signup-box'>
<div className='signup-forms'>
<h6>ID</h6>
<div id='forms-with-button'>
<div className='forms-with-btn'>
<input
placeholder='ID'
value={id}
onChange={(e) => setId(e.target.value)}
type='text'
name='id'
id='Id'
onBlur={handleFocus}
focused={focused.toString()}
required
/>
<span>
<img src={redWarning} alt={redWarning} />
Please fill ID
</span>
</div>
<div>
<button onSubmit={CheckUser}>CheckUser</button>
</div>
</div>
</div>
<div className='signup-forms'>
<div className='pw-box'>
<h6>Password</h6>
<p>
<img src={warning} alt={warning} /> Password should be 8-20 characters and include at least 1 letter, 1 number and 1 special character!
</p>
</div>
<div className='forms-without-btn'>
<input
placeholder='Please type password'
value={password}
onChange={(e) => setPassword(e.target.value)}
type='password'
name='password'
id='password'
autoComplete='off'
pattern={`^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[!##$%^&*])[a-zA-Z0-9!##$%^&*]{8,20}$`}
onBlur={handleFocus}
focused={focused.toString()}
required
></input>
<input
placeholder='Repeat the password'
value={passwordConfirm}
onChange={(e) => setPasswordConfirm(e.target.value)}
type='password'
name='passwordConfirm'
id='pwRepeat'
autoComplete='off'
onBlur={handleFocus}
focused={focused.toString()}
pattern={`^(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[!##$%^&*])[a-zA-Z0-9!##$%^&*]{8,20}$`}
onFocus={() =>
password === "passwordConfirm" && setFocused(true)
}
required
></input>
<span>
<img src={redWarning} alt={redWarning} />
Passwords don't match !
</span>
</div>
</div>
<div className='signup-forms'>
<h6>Name</h6>
<div className='forms-without-btn'>
<input
placeholder='Type your name'
value={name}
onChange={(e) => setName(e.target.value)}
type='text'
name='name'
id='Name'
autoComplete='off'
pattern={`^[가-힣]{2,4}$`}
focused={focused.toString()}
onBlur={handleFocus}
required
></input>
<span>
<img src={redWarning} alt={redWarning} />
Check your name
</span>
</div>
</div>
<div className='signup-forms'>
<h6>Phone</h6>
{isPhonecertiOn === true ? (
<PhoneCertificate
isPhonecertiOn={isPhonecertiOn}
setPhoneCertiOn={setPhoneCertiOn}
/>
) : (
<div id='forms-with-button'>
<div className='forms-with-btn'>
<input
// style={style}
placeholder='Enter your phone'
value={phone}
onChange={(e) => setPhone(e.target.value)}
type='text'
name='phone'
id='Phone'
autoComplete='off'
pattern={`^(010|011|016|017|018|019)[0-9]{3,4}[0-9]{4}$`}
focused={focused.toString()}
required
></input>
<span>
<img src={redWarning} alt={redWarning} />
Phone has 11 digits
</span>
</div>
<div>
<button
id='phone-certification'
onClick={() => setPhoneCertiOn(true)}
>
<img src={phone_certi} alt={phone_certi} />
Phone Certification
</button>
</div>
</div>
)}
</div>
<span>
<img src={redWarning} alt={redWarning} />
Phone has 11 digits.
</span>
<div className='signup-forms'>
<h6>Email</h6>
{isEmailcertiOn === true ? (
<EmailCertificate
isEmailcertiOn={isEmailcertiOn}
setEmailcertiOn={setEmailcertiOn}
/>
) : (
<div id='forms-with-button'>
<div className='forms-with-btn'>
<input
// style={style}
placeholder='Type your email'
value={email}
onChange={(e) => setEmail(e.target.value)}
type='text'
name='email'
id='email'
autoComplete='off'
onBlur={handleFocus}
focused={focused.toString()}
required
></input>
<span>
<img src={redWarning} alt={redWarning} />
Please enter exact email form
</span>
</div>
<div>
<button
id='email-certification'
onClick={() => setEmailcertiOn(true)}
>
<img src={email_certi} alt={email_certi} />
Email certification
</button>
</div>
</div>
)}
</div>
<div className='signup-forms'>
<button id='signup-btn'>Submit</button>
<button
id='signup-cancle-btn'
onClick={() => {
props.setFormsOn(false);
}}
>
Cancle
</button>
</div>
</div>
</div>
</form>
</div>
</div>
}
I believe the most comprehensive solution to this problem is as follows:
Have a isValid state for each form input.
Have the validation check function sets the isValid state for all inputs.
I have an example of a form component that you can use as a reference although it is implemented in typescript so the syntax will be slightly different.
Example
const LoginForm = ({email, setEmail, password, setPassword, onLogin, loading}: LoginFormPropTypes) => {
const [isVisiblePassword, setIsVisiblePassword] = useState(false);
const [validEmail, setValidEmail] = useState(true);
const [emailHelper, setEmailHelper] = useState<string | null>(null);
const [validPassword, setValidPassword] = useState(true);
const [passwordHelper, setPasswordHelper] = useState<string | null>(null);
const {colors} = useTheme();
// Setting form validation states and helperText using validator
const validateForm = (input: 'email' | 'password' | 'all') => {
let allowSubmit = true;
if(input === 'email' || input === 'all') {
if(!validator.isLength(email, {min: 1})) {
setValidEmail(false);
setEmailHelper('Email field cannot be empty');
allowSubmit = false;
} else if(!validator.isEmail(email) || !validator.isLength(email, {max: 320})){
setValidEmail(false);
setEmailHelper('The Email provided is invalid');
allowSubmit = false;
} else {
setValidEmail(true);
}
}
if(input === 'password' || input === 'all') {
if(!validator.isLength(password, {min: 1})) {
setValidPassword(false);
setPasswordHelper('Password field cannot be empty');
allowSubmit = false;
} else if(!validator.isLength(password, {max: 200})) {
setValidPassword(false);
setPasswordHelper('Password exceeds maximum length of 200')
allowSubmit = false;
} else {
setValidPassword(true);
}
}
return allowSubmit;
}
// Checking if form is valid before submitting
const onSubmitHandler = () => {
if(validateForm('all')){
onLogin?.();
}
}
return (
<CardWrapper>
<Card.Content>
<TextInput
label="Email"
mode="outlined"
style={styles.textInput}
onChangeText={setEmail}
value={email}
dense
error={!validEmail}
onBlur={() => {validateForm('email')}}
/>
<HelperText
type="error"
visible={!validEmail}
style={{display: !validEmail ? undefined : 'none'}}
>
{emailHelper}
</HelperText>
<TextInput
label="Password"
mode="outlined"
style={{...styles.textInput, ...styles.marginTop}}
onChangeText={setPassword}
value={password}
dense
secureTextEntry={!isVisiblePassword}
onBlur={() => {validateForm('password')}}
right={
<TextInput.Icon
color={(isFocused) =>
validPassword
? (isFocused ? colors.primary : 'black')
: colors.error
}
forceTextInputFocus={false}
onPress={() => setIsVisiblePassword(!isVisiblePassword)}
name={isVisiblePassword ? "eye-off" : "eye"}
/>
}
error={!validPassword}
/>
<HelperText
type="error"
visible={!validPassword}
style={{display: !validPassword ? undefined : 'none'}}
>
{passwordHelper}
</HelperText>
<Button
style={{marginTop: 15}}
mode="contained"
onPress={onSubmitHandler}
loading={loading}
>
Login
</Button>
</Card.Content>
</CardWrapper>
);
};

React - multi step form with checkbox in child step does not set to true

I am creating a multistep form in react. The Parent component has 3 child components which are the steps of the form. In the first step I have 4 text inputs and need a checkbox to allow wpp communication, the problem is that i can't set the state of the checkbox to true when is clicked.
The parent component is something like this:
import React from 'react';
import FormStep0 from './formStepZero';
import FormStep1 from './formStepOne';
class VendeForm extends React.Component {
constructor(props) {
super(props)
this.state = {
currentStep: 0,
nombre: '',
apellido: '',
celular: '',
email: '',
username: '',
password: '',
checkbox: false,
}
}
handleChange = event => {
const {name, value} = event.target
this.setState({
[name]: value
})
}
handleSubmit = event => {
event.preventDefault()
const { email, username, password, nombre, apellido, celular,checkbox } = this.state
alert(`Your registration detail: \n
Email: ${email} \n
Username: ${username} \n
Password: ${password} \n
Nombre: ${nombre} \n
Apellido: ${apellido} \n
Celular: ${celular} \n
Checkbox: ${checkbox} \n`)
}
_next = () => {
let currentStep = this.state.currentStep
currentStep = currentStep >= 2? 3: currentStep + 1
this.setState({
currentStep: currentStep
})
}
_prev = () => {
let currentStep = this.state.currentStep
currentStep = currentStep <= 0? 0: currentStep - 1
this.setState({
currentStep: currentStep
})
}
/*
* the functions for our button
*/
previousButton() {
let currentStep = this.state.currentStep;
if(currentStep > 1){
return (
<div className='vertical-center'>
<button
className="btn btn-secondary float-right mx-2 my-2"
type="button" onClick={this._prev}>
Previous
</button>
</div>
)
}
return null;
}
nextButton(){
let currentStep = this.state.currentStep;
if(currentStep <3 && currentStep >=1){
return (
<div className='vertical-center'>
<button
className="btn primary-bg-style float-left mx-2 my-2"
type="button" onClick={this._next}>
Siguiente
</button>
</div>
)
}
return null;
}
empecemosButton(){
let currentStep = this.state.currentStep;
if(currentStep === 0){
return (
<div className='vertical-center'>
<button
className="btn primary-bg-style"
type="button" onClick={this._next}>
Vamos!
</button>
</div>
)
}
return null;
}
render() {
return (
<React.Fragment>
{/*render the form steps and pass required props in*/}
<Step0
currentStep={this.state.currentStep}
handleChange={this.handleChange}
/>
<div className="container d-flex flex-column py-2">
<form onSubmit={this.handleSubmit}>
<Step1
currentStep={this.state.currentStep}
handleChange={this.handleChange}
nombre={this.state.nombre}
apellido={this.state.apellido}
celular={this.state.celular}
email={this.state.email}
checkbox={this.state.checkbox}
/>
<Step2
currentStep={this.state.currentStep}
handleChange={this.handleChange}
username={this.state.username}
/>
<Step3
currentStep={this.state.currentStep}
handleChange={this.handleChange}
password={this.state.password}
/>
</form>
<div className='prev-next-btn'>
{this.previousButton()}
{this.nextButton()}
</div>
{this.empecemosButton()}
</div>
</React.Fragment>
);
}
}
function Step0(props){
if (props.currentStep !== 0) {
return null
}
return(
<div className="vertical-center"> {/*<!--^--- Added class --> */}
...
</div>
)
}
function Step1(props) {
if (props.currentStep !== 1) {
return null
}
return(
<div className="form-group">
<div className="vertical-center">
<div className="container">
<h1 className='pb-4 px-2'>Datos de Contacto</h1>
<CircleSteps currentStep={props.currentStep} />
<FormStep1 nombre={props.nombre}
apellido={props.apellido}
celular={props.celular}
email={props.email}
checkbox={props.checkbox}
handleChange = {props.handleChange}
/>
</div>
</div>
</div>
);
}
export default VendeForm;
and the child component where is the checkbox is:
import React from 'react';
import {Col, Row,Container} from 'reactstrap'
function FormStep1(props) {
return(
<div>
<Container className="vende-form-container pt-3">
<Row className='align-items-center justify-content-center'>
<Col md={4} sm={12}>
<div className="form-group">
<label htmlFor="nombre">Nombre</label>
<input
className="form-control"
id="nombre"
name="nombre"
type="text"
placeholder="Escribe tu nombre"
value={props.nombre}
onChange={props.handleChange}
/>
</div>
</Col>
<Col md={4} sm={12} >
<div className="form-group">
<label htmlFor="apellido">Apellido</label>
<input
className="form-control"
id="apellido"
name="apellido"
type="text"
placeholder="Escribe tu apellido"
value={props.apellido}
onChange={props.handleChange}
/>
</div>
</Col>
</Row>
<Row className='align-items-center justify-content-center'>
<Col md={4} sm={12}>
<div className="form-group">
<label htmlFor="celular">Celular</label>
<input
className="form-control"
id="celular"
name="celular"
type="text"
placeholder="Escribe tu celular"
value={props.celular}
onChange={props.handleChange}
/>
</div>
</Col>
<Col md={4} sm={12}>
<div className="form-group">
<label htmlFor="email">Email</label>
<input
className="form-control"
id="email"
name="email"
type="text"
placeholder="Escribe tu email"
value={props.email}
onChange={props.handleChange}
/>
</div>
</Col>
</Row>
<Row className='align-items-center justify-content-start'>
{/* checkbox allowing whatsapp communication */}
<Col sm={{size:6, offset:2}} md={{size:3, offset:2}}>
<div className="form-check">
<input
className="form-check-input"
id="wppCheckbox"
name="controlled"
type="checkbox"
checked={props.checkbox}
onChange={props.handleChange}
/>
<label className="form-check-label" htmlFor="wppCheckbox">
Aceptas comunicacion via Whatsapp
</label>
</div>
</Col>
</Row>
</Container>
</div>
);
}
export default FormStep1;
The behavior that currently I have is that i click the checkbox but remains in blank, also the others fields of the form are working well and are passed to state properly
If I understand correctly, your checkbox is handled by generic handleChange() function:
handleChange = event => {
const {name, value} = event.target
this.setState({
[name]: value
})
}
Simplest thing you could try for debugging is just logging what you get in that function when you click the checkbox. Most probably in this case you are always getting the same value ("on") hence nothing changes in the state.
I would suggest either use a dedicated handler, or modify this one to be sth like
handleChange = event => {
const {name, type, value} = event.target
if (type === 'checkbox') {
return this.setState({
[name]: event.target.checked
})
}
this.setState({
[name]: value
})
}

How to reset the Modal input states after clicking the modal close button in React?

After giving the input of mobile number when i close the modal, then again after clicking the Form Submit button, input box shows the previously entered number. I believe model captures the previous state by itself and i want to clear it whenever we open the modal.
After entering the OTP input in Modal, if we click on the Edit mobile number and when we again enter the input in mobile number, then previously entered OTP also shows up. I want to clear it after entering the new mobile number.
I have already tried setting the state to ("") on the onclick events but it doesn't help.
I could really use some help.
Code:
export default function Form() {
// form default hooks
const {register,handleSubmit, formState: { errors, isValid },} = useForm({mode: "onChange",criteriaMode: "all",});
const {register: register2,handleSubmit: handleSubmit2,formState: { errors: errors2 },} = useForm({mode: "onChange",});
const [verifyOTPFlag, setVerifyOTPFlag] = useState(true);
//modal hooks
const [mobileNumberInput, setMobileNumberInput] = useState(true);
const [postVerificationMessage, setPostVerificationMessage] = useState();
const [otpVerificationResult, setOtpVerificationResult] = useState(false);
const [show, setShow] = useState(false);
const [otpInput, setShowOtpInput] = useState(false);
const [number, setNumber] = useState("");
const [OTP, setOTP] = useState("");
const [counter, setCounter] = useState(59);
// post office and aadhar hooks
const [districtName, setDistrictName] = React.useState("");
const [stateName, setStateName] = React.useState("");
//-------------------------modal functionalities start-------------------------
const handleClose = () => {
setShow(false);
setShowOtpInput(false);};
const handleShow = () => {
setShow(true);};
const showOtpInput = () => {
getOTP(number);
setOTP("");
setShowOtpInput(true);
setMobileNumberInput(false);
setOtpVerificationResult(false);
};
const onSubmit = (data) => {
data["district"] = districtName;
data["state"] = stateName;
setMobileNumberInput(true);
setPostVerificationMessage("");
setNumber("");
if (verifyOTPFlag) {
if (isValid) {
setShow(true);
} else {}
}
};
const onSubmit2 = () => {
verifyOTP(OTP)
.then((resp) => {
alert("OTP verification Successful");
setPostVerificationMessage(<p className="text-danger">OTP verification Successful</p>);
setVerifyOTPFlag(false);
setOtpVerificationResult(true);
setShowOtpInput(false);
})
.catch((error) => {
setPostVerificationMessage(<p className="text-danger"> OTP verification Failed. Kindly enter the correct OTP</p> )
setOtpVerificationResult(true);
});};
const onClickEditMobileNo = () => {
setShowOtpInput(!otpInput);
setOtpVerificationResult("");
setOTP("");
setMobileNumberInput(true);
};
return (
<div>
<div className="form-group">
<form onSubmit={handleSubmit(onSubmit)}>
<div className="container mt-2">
<label className="control-label">Full Name : </label>
<input
className="text-uppercase input-group input-group-lg form-control"
type="text"
name="username"
{...register("username", {
required: "Username is Required",
pattern: {
value: /^[a-zA-Z0-9\s,\'-\/:&]*$/,
message: "Entered value does not match valid name format",
},
})}
/>
<p className="errorMsg">{errors.username?.message}</p>
<label className="control-label">C/o : </label>
<input
className="text-uppercase input-group input-group-lg form-control"
type="text"
name="careof"
{...register("careof", {
required: "Name of c/o is Required",
pattern: {
value: /^[a-zA-Z0-9\s,\'-\/:&]*$/,
message: "Entered value does not match valid name format",
},
})}
/>
<p className="errorMsg">{errors.careof?.message}</p>
<label className="control-label">House No./Bldg./Apt : </label>
<input
className="text-uppercase input-group input-group-lg form-control"
type="text"
name="houseno"
{...register("houseno", {
required: "House number is Required",
})}
/>
<p className="errorMsg">{errors.houseno?.message}</p>
<div className="text-center">
<button
className="button btn-primary btn px-3 mr-1"
onClick={onSubmit}
>
Form Submit
</button>
</div>
</div>
</form>
<form onSubmit={handleSubmit2(onSubmit2)}>
{/* modal starts */}
<Modal show={show} onHide={handleClose} backdrop="static">
<Modal.Header
style={{
backgroundImage: "linear-gradient(180deg , #3f55c4 , #95a4f0",
}}
closeButton></Modal.Header>
<Collapse in={mobileNumberInput}>
<div
className="input-field-sb mt-4 ml-5"
style={{ width: "80%" }}
>
<input className="input-sb" maxLength="10" type="text" id="mobile"
// onChange={(e) => setNumber(e.target.value)}
{...register2("mobile", {
required: "Mobile number is Required",
pattern: {
value: /^[5-9]\d{9}$/,
message: "Entered value does not match valid name format",
},
onChange: (e) => setNumber(e.target.value),})}/>
<p className="errorMsg">{errors2.mobile?.message}</p>
<label className="label-sb" htmlFor="mobile">Enter Mobile Number: </label>
</div>
</Collapse>
<Modal.Body>
<Collapse in={otpInput}>
<div>
<div className="d-flex justify-content-center">
<p className="text-center"><strong>{" "} We sent you a code to verify your mobile number{" "}</strong>{" "}
<b className="text-danger">{number}</b>
<span className="mobile-text"> Enter your OTP code here</span>
</p>
</div>
<input className="input-sbj" maxLength="6" onChange={(e) => setOTP(e.target.value)}/>
</div>
</Collapse>
<Collapse in={otpVerificationResult}>
<div className="text-center">{postVerificationMessage}</div>
</Collapse>
<div className="d-flex justify-content-center col-md-12">
{otpInput ? (
<Button className="px-5 align-middle mt-4" variant="secondary" onClick={onSubmit2}>{" "} Verify</Button>) : (
<Button className="px-5 align-middle mt-4" variant="secondary"
onClick={errors2.mobile ? null : showOtpInput}>
{" "} Send OTP </Button>)}
</div>
<div className="row">
<div className={otpInput ? "col-sm-6" : "col-sm-6 d-none"}>
<a className="btn">Resend OTP in 00:{counter}</a>
</div>
<div
className={otpInput? "text-right col-sm-6": "text-right col-sm-6 d-none"}>
<a className="btn" onClick={onClickEditMobileNo}> Edit Mobile number </a>
</div>
</div>
</Modal.Body>
</Modal>
</form>
{/* modal ends */}
</div></div>);}
The easiest way would be just adding e.target.reset() in your onSubmit function.
const onSubmit = (data, e) => {
data["district"] = districtName;
data["state"] = stateName;
setMobileNumberInput(true);
setPostVerificationMessage("");
setNumber("");
e.target.reset();
if (verifyOTPFlag) {
if (isValid) {
setShow(true);
} else {}
}
};
also keep the setNumber("") like this. I think this will solve the problem.

Make Invalid Validation Disappear After 5 Seconds --ReactJS--

I'm trying to make the invalid feedback validation disappear after being on the screen for 5 seconds. in my state i have an empty errors object, when the form is submitted, the api call catches any errors from the backend, and they are placed in the errors object, the inputs use conditionals based on the errors object to show the validation. I've tried creating a setTimeout function that sets the state to an empty object after 5 seconds, but this causes breaking glitches if the form is submitted again incorrectly. Any insights how I can do this?
Register.js
import React, { Component } from "react";
import axios from 'axios';
import classnames from 'classnames';
class Register extends Component {
constructor(props) {
super(props);
this.state = {
name: "",
email: "",
password: "",
password2: "",
errors: {}
};
this.onChange = this.onChange.bind(this);
}
onChange(e) {
// THIS FUNCTION MUST BE BOUND -SEE ABOVE BIND
this.setState({
[e.target.name]: e.target.value
});
}
onSubmit = e => {
// ARROW FUNCTIONS DO NOT NEED TO BE BOUND
e.preventDefault();
const newUser = {
name: this.state.name,
email: this.state.email,
password: this.state.password,
password2: this.state.password2
};
this.setState({
email: "",
name: "",
password: "",
password2: ""
});
axios
.post("/api/users/register", newUser)
.then(res => console.log(res.data))
.catch(err => this.setState({ errors: err.response.data }));
};
render() {
const { errors } = this.state;
return (
<div>
<div className="register">
<div className="container">
<div className="row">
<div className="col-md-8 m-auto">
<h1 className="display-4 text-center text-dark">Sign Up</h1>
<p className="lead text-center">Create your DevMuse account</p>
<form onSubmit={this.onSubmit}>
<div className="form-group">
<input
type="text"
className={classnames("form-control form-control-lg", {
"is-invalid": errors.name
})}
placeholder="Name"
name="name"
value={this.state.name}
onChange={this.onChange}
/>
{errors.name && (
<div className="invalid-feedback">{errors.name}</div>
)}
</div>
<div className="form-group">
<input
type="email"
className={classnames("form-control form-control-lg", {
"is-invalid": errors.email
})}
placeholder="Email Address"
name="email"
value={this.state.email}
onChange={this.onChange}
/>
{errors.email ? (
<div className="invalid-feedback">{errors.email}</div>
) : (
<small className="form-text text-muted text-center">
This site uses Gravatar so if you want a profile image,
use a Gravatar email
</small>
)}
</div>
<div className="form-group">
<input
type="password"
className={classnames("form-control form-control-lg", {
"is-invalid": errors.password
})}
placeholder="Password"
name="password"
value={this.state.password}
onChange={this.onChange}
/>
{errors.password && (
<div className="invalid-feedback">{errors.password}</div>
)}
</div>
<div className="form-group">
<input
type="password"
className={classnames("form-control form-control-lg", {
"is-invalid": errors.password2
})}
placeholder="Confirm Password"
name="password2"
value={this.state.password2}
onChange={this.onChange}
/>
{errors.password2 && (
<div className="invalid-feedback">{errors.password2}</div>
)}
</div>
<input
type="submit"
className="btn btn-info btn-block mt-4"
/>
</form>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default Register;
Just clear any existing timeout before you initiate a new timeout:
componentWillUnmount() {
clearTimeout(this.clearError);
}
...
.catch((err) => {
this.setState({ errors: err.response.data });
clearTimeout(this.clearError); // clear previous timeout, if exists
this.clearError = setTimeout(() => {
this.setState({ errors: {} });
}, 5000);
});

Categories

Resources