Reset value of disabled Formik Field - javascript

I'm trying to clear/reset the value of a checkbox switch after it becomes disabled. I initially thought I had achieved this by using a React conditional and setting the value to an empty string but if the checkbox had been activated prior to being disabled then that value still gets submitted. This behaviour doesn't seem correct as I was under the impression that disabled input field values do not get submitted?
The React conditional says that if the form is disabled then the value of the checkbox should be empty.
I am using Formik to process forms with Yup schema validation.
Below is my entire code for the form.
Thank you, in advance.
import axios from "axios";
import * as Yup from "yup";
import Head from "next/head";
import Link from "next/link";
import Router from "next/router";
import { useState } from "react";
import Error from "../components/error";
import Layout from "../components/layout";
import Button from "react-bootstrap/Button";
import Spinner from "react-bootstrap/Spinner";
import { Formik, Form, Field, ErrorMessage } from "formik";
var instagram = false;
var twitter = false;
var github = false;
const validationSchema = Yup.object({
firstName: Yup.string()
.max(15, "Must be 15 characters or less"),
email: Yup.string().email("Invalid email address").required("Required"),
username: Yup.string()
.test(
'valid-instagram', "Instagram: may contain only alphanumeric characters, periods, and underscores", function (username){
var instagramRegex = new RegExp(/^(?!.*\.\.)(?!.*\.$)[^\W][\w.]{0,29}$/);
var instagramRes = instagramRegex.test(username)
if (instagramRes) { // if res is true then the username is valid and the switch can be enabled
instagram = false;
return true // return true to tell Yup the field is valid
} else {
instagram = true;
return true // true removes error message
}
}
)
.test(
'valid-twitter', "Twitter: may only contain alphanumeric characters or underscores", function (username){
var twitterRegex = new RegExp(/^[A-Za-z0-9_]{1,15}$/);
var twitterRes = twitterRegex.test(username)
if (twitterRes) { // if res is true then the username is valid and the switch can be enabled
twitter = false;
return true // return true to tell Yup the field is valid
} else {
twitter = true;
return true // true removes error message
}
}
)
.test(
'valid-github', "GitHub: may only contain alphanumeric characters or single hyphens", function (username){
var githubRegex = new RegExp(/^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i);
var githubRes = githubRegex.test(username)
if (githubRes) { // if res is true then the username is valid and the switch can be enabled
github = false;
return true // return true to tell Yup the field is valid
} else {
github = true;
return true // true removes error message
}
}
)
.required("Required"),
acceptTerms: Yup.boolean()
.required("Required")
.oneOf([true], "You must accept the terms and conditions."),
switchGroup: Yup.array().required("At least one option must be selected"),
});
const initialValues = {
firstName: "",
email: "",
username: "",
acceptTerms: false, // added for our checkbox
switchGroup: [], // array for switches
};
export default function Signup() {
const [error, setError] = useState("");
return (
<Layout>
<Head>
<title>Signup - Notify.is</title>
</Head>
<div className="container-center">
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={async (values, { setSubmitting }) => {
const data = new URLSearchParams(values);
const res = await axios
.post("http://localhost:8080/api/signup", data)
.then((response) => {
Router.push("/thanks");
})
.catch((error) => {
setError(error.message);
});
setSubmitting(false);
}}
>
{({ touched, errors, isSubmitting }) => (
<Form className="form">
<h1 className="display-4 pb-3">Get notified</h1>
<div className="form-label-group">
<Field
type="text"
name="firstName"
id="firstName"
placeholder="First name"
className={`form-control ${
touched.firstName && errors.firstName
? "is-invalid"
: null
}`}
/>
<label htmlFor="firstname">First name</label>
<small id="nameHelp" className="form-text text-muted">
Optional
</small>
</div>
<div className="form-label-group">
<Field
type="email"
name="email"
id="email"
placeholder="Email address"
className={`form-control ${
touched.email && errors.email ? "is-invalid" : null
}`}
/>
<ErrorMessage
component="div"
name="email"
className="invalid-feedback"
/>
<small id="emailHelp" className="form-text text-muted">
We'll never share your email with anyone else.
</small>
<label htmlFor="email">Email address</label>
</div>
<div className="form-label-group">
<Field
type="text"
name="username"
id="username"
autoCorrect="off"
autoCapitalize="none"
placeholder="Username"
className={`form-control ${
touched.username && errors.username ? "is-invalid" : null
}`}
/>
<ErrorMessage
component="div"
name="username"
className="invalid-feedback"
/>
<small id="usernameHelp" className="form-text text-muted">
The unavailable username you want.
</small>
<label htmlFor="username">Username</label>
</div>
<div>
<div className="custom-control custom-switch">
<Field
type="checkbox"
name="switchGroup"
id="instagram-switch"
value={instagram ? "" : "instagram"}
disabled={instagram}
className={`custom-control-input ${
touched.switchGroup && errors.switchGroup
? "is-invalid"
: null
}`}
/>
<label
className="custom-control-label"
htmlFor="instagram-switch"
>
Instagram
</label>
</div>
<div className="custom-control custom-switch">
<Field
type="checkbox"
name="switchGroup"
id="twitter-switch"
value={twitter ? "" : "twitter"}
disabled={twitter}
className={`custom-control-input ${
touched.switchGroup && errors.switchGroup
? "is-invalid"
: null
}`}
/>
<label
className="custom-control-label"
htmlFor="twitter-switch"
>
Twitter
</label>
</div>
<div className="custom-control custom-switch">
<Field
type="checkbox"
name="switchGroup"
id="github-switch"
value={github ? "" : "github"}
disabled={github}
className={`custom-control-input ${
touched.switchGroup && errors.switchGroup
? "is-invalid"
: null
}`}
/>
<label
className="custom-control-label"
htmlFor="github-switch"
>
GitHub
</label>
<ErrorMessage
component="div"
name="switchGroup"
className="invalid-feedback"
/>
</div>
<small id="usernameHelp" className="form-text text-muted">
The service(s) we should check with.
</small>
</div>
<div className="custom-control custom-checkbox pt-3 mb-1">
<Field
type="checkbox"
name="acceptTerms"
id="acceptTerms"
className={`custom-control-input ${
touched.acceptTerms && errors.acceptTerms
? "is-invalid"
: null
}`}
/>
<label htmlFor="acceptTerms" className="custom-control-label">
By checking this box you agree to our:
</label>
<ErrorMessage
component="div"
name="acceptTerms"
className="invalid-feedback"
/>
</div>
<span className="grey termslabel">
<Link href="/tos">
<a className="terms" target="_blank">
Terms of Use
</a>
</Link>{" "}
and{" "}
<Link href="/privacy">
<a className="terms" target="_blank">
Privacy Policy
</a>
</Link>
</span>
<Button
className="btn-lg btn-primary btn-block mt-4"
variant="primary"
disabled={isSubmitting, error}
type="submit"
>
{isSubmitting && (
<Spinner
as="span"
animation="grow"
size="lg"
role="status"
aria-hidden="true"
/>
)}
{isSubmitting && <span> Submitting...</span>}
{!isSubmitting && <span>Sign up</span>}
</Button>
{error ? <Error error={error} /> : null}
<p className="mt-4 mb-3 text-muted text-center">
© Notify.is 2020
</p>
</Form>
)}
</Formik>
</div>
<style jsx>
{`
.display-4 {
font-weight: 700;
}
.terms {
text-decoration: underline;
}
.terms:hover {
text-decoration: none;
}
`}
</style>
</Layout>
);
}

I ended up managing to do what I wanted in a different way than originally intended, but it works well.
Using the Boolean variables that change value based on whether a field should be disabled, I did an if statement for each one within the Formik onSubmit prop and changed the values within the array at the indexes of the values that should be omitted.
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={async (values, { setSubmitting }) => {
// if the field was disabled then don't submit switch value
if (instagram) {
var i = values.switchGroup.indexOf("instagram");
values.switchGroup[i] = null
}
if (twitter) {
var i = values.switchGroup.indexOf("twitter");
values.switchGroup[i] = null
}
if (github) {
var i = values.switchGroup.indexOf("github");
values.switchGroup[i] = null
}
const data = new URLSearchParams(values);
const res = await axios
.post("/api/signup", data)
.then((response) => {
Router.push("/thanks");
})
.catch((error) => {
setError(error.message);
});
setSubmitting(false);
}}
>

Check out the FieldArray component. Its' render prop provides an arrayHelper for adding/removing values from fieldArrays.

Related

How to trigger modal from a different component

1st component (here is the modal)
import './Register.css';
import {useFormik} from 'formik';
import * as Yup from 'yup';
import {useNavigate} from 'react-router-dom';
import {registerUser} from '../../services/auth.service';
import {
createUser,
getUserByUsername,
} from '../../services/user.request.services.js';
import {useContext} from 'react';
import AppContext from '../../context/AppContext.js';
export default function Register() {
const navigate = useNavigate();
const {addToast} = useContext(AppContext);
const formik = useFormik({
initialValues: {
username: '',
firstName: '',
lastName: '',
email: '',
password: '',
},
validationSchema: Yup.object({
username: Yup.string()
.max(50, 'Username must be maximum 50 symbols')
.required('Please, choose username.')
.min(4, 'username must be minimum 4 symbols'),
firstName: Yup.string()
.max(32, 'Last name must be maximum 32 symbols')
.min(4, 'First name must be minimum 4 symbols')
.required('You need to apply first name!'),
lastName: Yup.string()
.max(32, 'First name must be maximum 32 symbols')
.min(4, 'Last name must be minimum 4 symbols')
.required('You need to apply last name!'),
email: Yup.string()
.email('Must be a valid email address')
.required('Email is required!'),
password: Yup.string().required('Please, type your password.'),
}),
onSubmit: async (values) => {
try {
const user = await getUserByUsername(values.username);
if (user !== null) {
formik.errors.username = 'Username already in use!';
return;
}
const credentials = await registerUser(values.email, values.password);
try {
await createUser(
values.firstName,
values.lastName,
values.email,
values.username,
credentials.user.uid,
);
} catch (error) {
addToast('error', 'Something went wrong!');
}
} catch (error) {
if (error.message.includes('auth/email-already-in-use')) {
formik.errors.email = 'This email is already in use!';
return;
}
addToast('error', 'Something went wrong');
}
addToast('success', 'You have been registered!');
addToast('success', 'Welcome to the UnHOOman Forum!');
navigate('/');
},
});
const resetFormHandler = () => {
formik.resetForm();
};
return (
<>
<label htmlFor="register-modal">
<p className="cursor-pointer">Register</p>
</label>
<input type="checkbox" id="register-modal" className="modal-toggle" />
<div className="modal modal-bottom sm:modal-middle">
<div className="modal-box min-h-1/2">
<div className="modal-action m-0 justify-center gap-2 h-full border-2 border-[#F79E47]">
<form onSubmit={formik.handleSubmit} className="w-full">
<div className='form-wrapper'>
<h1 className="font-bold">Register</h1>
<input
type="text"
placeholder="Username..."
name="username"
value={formik.values.username}
onBlur={formik.handleBlur}
onChange={formik.handleChange}
className="input w-full input-bordered border-[#F79E47] max-w-xs block"
/>
{formik.touched.username && formik.errors.username ? (
<p className="text-red-700 text-sm">{formik.errors.username}</p>
) : null}
<input
type="text"
placeholder="First name..."
name="firstName"
value={formik.values.firstName}
onBlur={formik.handleBlur}
onChange={formik.handleChange}
className="input input-bordered border-[#F79E47] w-full max-w-xs"
/>
{formik.touched.firstName && formik.errors.firstName ? (
<p className="text-red-700 text-sm">{formik.errors.firstName}</p>
) : null}
<input
type="text"
placeholder="Last name..."
name="lastName"
value={formik.values.lastName}
onBlur={formik.handleBlur}
onChange={formik.handleChange}
className="input input-bordered border-[#F79E47] w-full max-w-xs"
/>
{formik.touched.lastName && formik.errors.lastName ? (
<p className="text-red-700 text-sm">{formik.errors.lastName}</p>
) : null}
<input
type="email"
placeholder="Email..."
name="email"
value={formik.values.email}
onBlur={formik.handleBlur}
onChange={formik.handleChange}
className="input input-bordered border-[#F79E47] w-full max-w-xs"
/>
{formik.touched.email && formik.errors.email ? (
<p className="text-red-700 text-sm">{formik.errors.email}</p>
) : null}
<input
type="password"
placeholder="Password..."
name="password"
value={formik.values.password}
onBlur={formik.handleBlur}
onChange={formik.handleChange}
className="input input-bordered border-[#F79E47] w-full max-w-xs"
/>
{formik.touched.password && formik.errors.password ? (
<p className="text-red-700 text-sm">{formik.errors.password}</p>
) : null}
<div className="signup-buttons">
<label
type="button"
htmlFor="register-modal"
className="btn btn-outline"
onClick={() => resetFormHandler()}
>
CANCEL
</label>
<button type="submit" className="btn btn-outline">
Submit
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</>
);
}
2nd component from which I want to be able to trigger the modal
import {HOME_CARD_TITLE, HOME_CARD_DESC} from '../../common/constants.js';
import {useContext, useEffect, useState} from 'react';
import {getAllPosts} from '../../services/posts.service.js';
import {getAllUsers} from '../../services/user.request.services.js';
import AppContext from '../../context/AppContext.js';
import {Navigate, useNavigate} from 'react-router-dom';
export default function HomeInfoCard() {
const [cardState, setCardState] = useState({posts: 0, members: 0});
const {addToast} = useContext(AppContext);
const navigate = useNavigate();
useEffect(() => {
const updatePostsAndUsers = async () => {
const posts = (await getAllPosts()).length;
const members = (await getAllUsers()).length;
setCardState((prev) => ({
...prev,
posts,
members,
}));
};
updatePostsAndUsers().catch((error) => addToast('error', error.message));
}, []);
return (
<div className="card max-w-md bg-base-100 shadow-xl">
<div className="card-body">
<h2 className="card-title">{ HOME_CARD_TITLE }</h2>
<p className="mb-3">{ HOME_CARD_DESC }</p>
<div className="stats shadow text-center mb-3">
<div className="stat">
<div className="stat-title">Posts</div>
<div className="stat-value">{ cardState.posts }</div>
</div>
<div className="stat">
<div className="stat-title">Members</div>
<div className="stat-value">{ cardState.members }</div>
</div>
</div>
<div className="card-actions justify-center">
<button className="btn bg-[#FCDDBF] border-0 text-[#4A4846] hover:text-[#fff] w-full" onClick={() => navigate('/login')}>Join community</button>
</div>
</div>
</div>
);
}
I have two components, the first one is a register form with Formik and there is also a modal from daisyUI.
I have a 'View community button' in other component which I want to be able to make on click to open the register form modal from the other component, but I couldn't find a solution for this problem.
I've tried with data-toggle/data-target, but it didn't work.
The button which I want to be able to trigger the modal from the register component is in the end of the second component and it's currently leading to the home page with useNavigate.
I am not a professional programmer, and currently I am in a boot camp, so that's why the code is trashy, but we all start from somewhere. Thanks in advance for the replies!

Modal pop up on submit in React

I am trying to display a modal pop up on submit in a form in React. Right now, the invalid email and name modal pops up just fine. The problem is, It will not display the alternate success message if the form was submitted correctly. I also am not sure if it will persist upon successful submission, but can't get past this problem to test it out. Please let me know where I am going wrong. Thanks!!
Contact.js:
import React, { useState } from "react";
import { FaEnvelope } from "react-icons/fa";
import Modal from "./Modal";
const Contact = (props) => {
const [showModal, setShowModal] = useState();
const [enteredName, setEnteredName] = useState("");
const [enteredEmail, setEnteredEmail] = useState("");
const contactHandler = (event) => {
event.preventDefault();
if (enteredName.trim().length === 0 || enteredEmail.trim().length === 0) {
setShowModal({
title: "Invalid Input",
message: "Please enter a valid name and email",
});
return;
}
if (enteredName.trim().length > 0 || enteredEmail.trim().length > 0) {
setShowModal({
title: "Thank You",
message: "Your form as been submitted",
});
return;
}
props.Contact(enteredName, enteredEmail);
setEnteredName("");
setEnteredEmail("");
};
const modalHandler = () => {
setShowModal(null);
};
return (
<div>
{showModal && (
<Modal
title={showModal.title}
message={showModal.message}
onShowModal={modalHandler}
/>
)}
<div className="w-full h-screen main flex justify-center items-center p-4">
<form
onSubmit={contactHandler}
method="POST"
action="https://getform.io/f/8e30048c-6662-40d9-bd8b-da62595ce998"
className="flex flex-col max-w-[600px] w-full"
>
<div className="pb-8">
<p className="text-4xl font-bold inline border-b-4 bdr text-main">
Contact
</p>
<span>
<FaEnvelope className="inline-flex ml-4 text-4xl text-main" />
</span>
<p className="text-main py-2">
Please enter your info below and I will be back with you within 24
hours. You can also email me directly at:
<a
href="mailto:chris.t.williams417#gmail.com"
className="ml-2 font-bold hover:text-[#FFE5b4]"
>
chris.t.williams417#gmail.com
</a>
</p>
</div>
<input
className="form-bg p-2"
type="text"
placeholder="Name"
name="name"
/>
<input
className="my-4 py-2 form-bg"
type="email"
placeholder="Email"
name="email"
/>
<textarea
className="form-bg p-2"
name="message"
rows="10"
placeholder="Message"
></textarea>
<button className="con-btn">Submit</button>
</form>
</div>
</div>
);
};
export default Contact;
Modal.js:
import React from "react";
const Modal = (props) => {
return (
<div>
<div className="backdrop" onClick={props.onShowModal} />
<div className="modalPos">
<div className="header">
<h2>{props.title}</h2>
</div>
<div className="content">
<p>{props.message}</p>
</div>
<div className="actions">
<button onClick={props.onShowModal} className="hero-btn">
Exit
</button>
</div>
</div>
</div>
);
}
export default Modal
*disclaimer : my grammar so bad so i am apologize about that.
i just try your code and when i submit is always invalid, i check it and the state name and email is empty string when i submit because your forgot implement onChangeHanlde in input.
create function to handle onChange
const onChangeHandler = (field, event) => {
if (field == "email") {
setEnteredEmail(event.target.value);
} else if (field == "name") {
setEnteredName(event.target.value);
}
};
and add onChange, value attribute in input tag both name and email
<input
className="form-bg p-2"
type="text"
placeholder="Name"
name="name"
onChange={(e) => {
onChangeHandler("name", e);
}}
value={enteredName}
/>
<input
className="my-4 py-2 form-bg"
type="email"
placeholder="Email"
name="email"
onChange={(e) => {
onChangeHandler("email", e);
}}
value={enteredEmail}
/>
You didn't put
value = {enteredName}
in your input element. so your states will not be set by user's input.

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>
);
};

JS / JSX function always returns true even if it's false

I have a function in ReactJS that checks if string.trim() === "". The function should return false if none of the trimmed strings are equal to "", but it always returns true.
I take those strings from state.
import React, {Component} from 'react';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import './Contact.scss'
export default class Contact extends Component {
constructor(props) {
super(props);
this.state = {
name: "",
email: "",
subject: "",
message: ""
}
}
setName = (e) => {
this.setState({name: e.target.value});
};
setEmail = (e) => {
this.setState({email: e.target.value});
};
setSubject = (e) => {
this.setState({subject: e.target.value});
};
setMessage = (e) => {
this.setState({message: e.target.value});
};
validate = () => {
const { name, email, subject, message } = this.state;
return name.trim() === "" ||
email.trim() === "" ||
subject.trim() === "" ||
message.trim() === "";
};
render() {
const { name, email, subject, message } = this.state;
return (
<div id="Contact" className="Wrapper-contact">
<div className="Contact-container">
<div className="Contact-title">
HIT ME UP
</div>
<div className="Contact-content">
<form className="Form" action="https://formspree.io/a#gmail.com" method="POST">
<div className="Form-group">
<label>NAME</label>
<input
className="Form-field"
name="Name"
placeholder="Your Name"
value={name}
onChange={this.setName}
/>
</div>
<div className="Form-group">
<label>EMAIL</label>
<input
className="Form-field"
name="_replyto"
placeholder="Your Email"
value={email}
onChange={this.setEmail}
/>
</div>
<div className="Form-group">
<label>SUBJECT</label>
<input
className="Form-field"
name="Subject"
placeholder="Subject"
value={subject}
onChange={this.setSubject}
/>
</div>
<div className="Form-group">
<label>MESSAGE</label>
<textarea
className="Form-textarea"
name="Message"
placeholder="Your Message..."
rows="7"
value={message}
onChange={this.setMessage}
/>
</div>
<input type="hidden" name="_next" value="/"/>
<button
className="Contact-button"
type="submit"
disabled={!!this.validate() ? "true" : "false"}
>
SEND
</button>
</form>
<div className="Connect">
<span style={{padding: '5%'}}>Also, don't forget to connect with me!</span>
<a className="Connect-in" href="link" target="_blank" rel="noopener noreferrer">
<FontAwesomeIcon icon={['fab', 'linkedin']} size="2x"/>
</a>
</div>
</div>
</div>
</div>
)
}
}
And the function still returns true always.
You are not invoking the function, instead you are using its reference. Try to invoke it instead. Also you are using strings in expression blocks like {"true"}. So, it does not work like that. Try like this:
disabled={!!this.validate() ? true : false}
But, as you figured out yourself you can use your function without a ternary condition:
disabled={!!this.validate()}
Since it returns the boolean itself, not the string.
Apparently replacing
disabled={!!this.validate() ? "true" : "false"} with
disabled={!!this.validate()} did solve the problem.

How do I add validation to the form in my React component?

My Contact page form is as follows,
<form name="contactform" onSubmit={this.contactSubmit.bind(this)}>
<div className="col-md-6">
<fieldset>
<input ref="name" type="text" size="30" placeholder="Name"/>
<br/>
<input refs="email" type="text" size="30" placeholder="Email"/>
<br/>
<input refs="phone" type="text" size="30" placeholder="Phone"/>
<br/>
<input refs="address" type="text" size="30" placeholder="Address"/>
<br/>
</fieldset>
</div>
<div className="col-md-6">
<fieldset>
<textarea refs="message" cols="40" rows="20"
className="comments" placeholder="Message"/>
</fieldset>
</div>
<div className="col-md-12">
<fieldset>
<button className="btn btn-lg pro" id="submit"
value="Submit">Send Message</button>
</fieldset>
</div>
</form>
Need to add validation for all fields. Can anyone help me to add validation in this react form?
You should avoid using refs, you can do it with onChange function.
On every change, update the state for the changed field.
Then you can easily check if that field is empty or whatever else you want.
You could do something as follows :
class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
fields: {},
errors: {},
};
}
handleValidation() {
let fields = this.state.fields;
let errors = {};
let formIsValid = true;
//Name
if (!fields["name"]) {
formIsValid = false;
errors["name"] = "Cannot be empty";
}
if (typeof fields["name"] !== "undefined") {
if (!fields["name"].match(/^[a-zA-Z]+$/)) {
formIsValid = false;
errors["name"] = "Only letters";
}
}
//Email
if (!fields["email"]) {
formIsValid = false;
errors["email"] = "Cannot be empty";
}
if (typeof fields["email"] !== "undefined") {
let lastAtPos = fields["email"].lastIndexOf("#");
let lastDotPos = fields["email"].lastIndexOf(".");
if (
!(
lastAtPos < lastDotPos &&
lastAtPos > 0 &&
fields["email"].indexOf("##") == -1 &&
lastDotPos > 2 &&
fields["email"].length - lastDotPos > 2
)
) {
formIsValid = false;
errors["email"] = "Email is not valid";
}
}
this.setState({ errors: errors });
return formIsValid;
}
contactSubmit(e) {
e.preventDefault();
if (this.handleValidation()) {
alert("Form submitted");
} else {
alert("Form has errors.");
}
}
handleChange(field, e) {
let fields = this.state.fields;
fields[field] = e.target.value;
this.setState({ fields });
}
render() {
return (
<div>
<form
name="contactform"
className="contactform"
onSubmit={this.contactSubmit.bind(this)}
>
<div className="col-md-6">
<fieldset>
<input
ref="name"
type="text"
size="30"
placeholder="Name"
onChange={this.handleChange.bind(this, "name")}
value={this.state.fields["name"]}
/>
<span style={{ color: "red" }}>{this.state.errors["name"]}</span>
<br />
<input
refs="email"
type="text"
size="30"
placeholder="Email"
onChange={this.handleChange.bind(this, "email")}
value={this.state.fields["email"]}
/>
<span style={{ color: "red" }}>{this.state.errors["email"]}</span>
<br />
<input
refs="phone"
type="text"
size="30"
placeholder="Phone"
onChange={this.handleChange.bind(this, "phone")}
value={this.state.fields["phone"]}
/>
<br />
<input
refs="address"
type="text"
size="30"
placeholder="Address"
onChange={this.handleChange.bind(this, "address")}
value={this.state.fields["address"]}
/>
<br />
</fieldset>
</div>
</form>
</div>
);
}
}
React.render(<Test />, document.getElementById("container"));
In this example I did the validation only for email and name, but you have an idea how to do it. For the rest you can do it self.
There is maybe a better way, but you will get the idea.
Here is fiddle.
Try this, example,
the required property in the below input tag will ensure that the name field shouldn't be submitted empty.
<input type="text" placeholder="Your Name" required />
I've taken your code and adapted it with library react-form-with-constraints: https://codepen.io/tkrotoff/pen/LLraZp
const {
FormWithConstraints,
FieldFeedbacks,
FieldFeedback
} = ReactFormWithConstraints;
class Form extends React.Component {
handleChange = e => {
this.form.validateFields(e.target);
}
contactSubmit = e => {
e.preventDefault();
this.form.validateFields();
if (!this.form.isValid()) {
console.log('form is invalid: do not submit');
} else {
console.log('form is valid: submit');
}
}
render() {
return (
<FormWithConstraints
ref={form => this.form = form}
onSubmit={this.contactSubmit}
noValidate>
<div className="col-md-6">
<input name="name" size="30" placeholder="Name"
required onChange={this.handleChange}
className="form-control" />
<FieldFeedbacks for="name">
<FieldFeedback when="*" />
</FieldFeedbacks>
<input type="email" name="email" size="30" placeholder="Email"
required onChange={this.handleChange}
className="form-control" />
<FieldFeedbacks for="email">
<FieldFeedback when="*" />
</FieldFeedbacks>
<input name="phone" size="30" placeholder="Phone"
required onChange={this.handleChange}
className="form-control" />
<FieldFeedbacks for="phone">
<FieldFeedback when="*" />
</FieldFeedbacks>
<input name="address" size="30" placeholder="Address"
required onChange={this.handleChange}
className="form-control" />
<FieldFeedbacks for="address">
<FieldFeedback when="*" />
</FieldFeedbacks>
</div>
<div className="col-md-6">
<textarea name="comments" cols="40" rows="20" placeholder="Message"
required minLength={5} maxLength={50}
onChange={this.handleChange}
className="form-control" />
<FieldFeedbacks for="comments">
<FieldFeedback when="*" />
</FieldFeedbacks>
</div>
<div className="col-md-12">
<button className="btn btn-lg btn-primary">Send Message</button>
</div>
</FormWithConstraints>
);
}
}
Screenshot:
This is a quick hack. For a proper demo, check https://github.com/tkrotoff/react-form-with-constraints#examples
import React from 'react';
import {sendFormData} from '../services/';
class Signup extends React.Component{
constructor(props){
super(props);
this.state = {
isDisabled:true
}
this.submitForm = this.submitForm.bind(this);
}
validateEmail(email){
const pattern = /[a-zA-Z0-9]+[\.]?([a-zA-Z0-9]+)?[\#][a-z]{3,9}[\.][a-z]{2,5}/g;
const result = pattern.test(email);
if(result===true){
this.setState({
emailError:false,
email:email
})
} else{
this.setState({
emailError:true
})
}
}
handleChange(e){
const target = e.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
if(e.target.name==='firstname'){
if(e.target.value==='' || e.target.value===null ){
this.setState({
firstnameError:true
})
} else {
this.setState({
firstnameError:false,
firstName:e.target.value
})
}
}
if(e.target.name==='lastname'){
if(e.target.value==='' || e.target.value===null){
this.setState({
lastnameError:true
})
} else {
this.setState({
lastnameError:false,
lastName:e.target.value
})
}
}
if(e.target.name==='email'){
this.validateEmail(e.target.value);
}
if(e.target.name==='password'){
if(e.target.value==='' || e.target.value===null){
this.setState({
passwordError:true
})
} else {
this.setState({
passwordError:false,
password:e.target.value
})
}
}
if(this.state.firstnameError===false && this.state.lastnameError===false &&
this.state.emailError===false && this.state.passwordError===false){
this.setState({
isDisabled:false
})
}
}
submitForm(e){
e.preventDefault();
const data = {
firstName: this.state.firstName,
lastName: this.state.lastName,
email: this.state.email,
password: this.state.password
}
sendFormData(data).then(res=>{
if(res.status===200){
alert(res.data);
this.props.history.push('/');
}else{
}
});
}
render(){
return(
<div className="container">
<div className="card card-login mx-auto mt-5">
<div className="card-header">Register here</div>
<div className="card-body">
<form id="signup-form">
<div className="form-group">
<div className="form-label-group">
<input type="text" id="firstname" name="firstname" className="form-control" placeholder="Enter firstname" onChange={(e)=>{this.handleChange(e)}} />
<label htmlFor="firstname">firstname</label>
{this.state.firstnameError ? <span style={{color: "red"}}>Please Enter some value</span> : ''}
</div>
</div>
<div className="form-group">
<div className="form-label-group">
<input type="text" id="lastname" name="lastname" className="form-control" placeholder="Enter lastname" onChange={(e)=>{this.handleChange(e)}} />
<label htmlFor="lastname">lastname</label>
{this.state.lastnameError ? <span style={{color: "red"}}>Please Enter some value</span> : ''}
</div>
</div>
<div className="form-group">
<div className="form-label-group">
<input type="email" id="email" name="email" className="form-control" placeholder="Enter your email" onChange={(e)=>{this.handleChange(e)}} />
<label htmlFor="email">email</label>
{this.state.emailError ? <span style={{color: "red"}}>Please Enter valid email address</span> : ''}
</div>
</div>
<div className="form-group">
<div className="form-label-group">
<input type="password" id="password" name="password" className="form-control" placeholder="Password" onChange={(e)=>{this.handleChange(e)}} />
<label htmlFor="password">Password</label>
{this.state.passwordError ? <span style={{color: "red"}}>Please enter some value</span> : ''}
</div>
</div>
<button className="btn btn-primary btn-block" disabled={this.state.isDisabled} onClick={this.submitForm}>Signup</button>
</form>
</div>
</div>
</div>
);
}
}
export default Signup;
With React Hook, form is made super easy (React Hook Form: https://github.com/bluebill1049/react-hook-form)
i have reused your html markup.
import React from "react";
import useForm from 'react-hook-form';
function Test() {
const { useForm, register } = useForm();
const contactSubmit = data => {
console.log(data);
};
return (
<form name="contactform" onSubmit={contactSubmit}>
<div className="col-md-6">
<fieldset>
<input name="name" type="text" size="30" placeholder="Name" ref={register} />
<br />
<input name="email" type="text" size="30" placeholder="Email" ref={register} />
<br />
<input name="phone" type="text" size="30" placeholder="Phone" ref={register} />
<br />
<input name="address" type="text" size="30" placeholder="Address" ref={register} />
<br />
</fieldset>
</div>
<div className="col-md-6">
<fieldset>
<textarea name="message" cols="40" rows="20" className="comments" placeholder="Message" ref={register} />
</fieldset>
</div>
<div className="col-md-12">
<fieldset>
<button className="btn btn-lg pro" id="submit" value="Submit">
Send Message
</button>
</fieldset>
</div>
</form>
);
}
Assuming you know about react useState Hook, If your form is simple, you can use state variables to hold the value of each input field. Then add onChange handler function on each input field which will update state variables. At the end, you can check the values stored in state variables to ensure that all the input fields had some value. Here is a simple example.
import { useState } from "react";
export default function App() {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const onChangeHandler = (fieldName, value)=>{
if(fieldName === "name"){
setName(value);
}
else if(fieldName==="email"){
setEmail(value);
}
}
const onSubmitHandler = (e)=>{
e.preventDefault();
if(name.trim()==="" || email.trim() ==""){
alert("required both field");
}
else{
alert(name+" " +email);
setName("");
setEmail("");
}
}
return (
<div className="App">
<form onSubmit={(e)=>{onSubmitHandler(e)}}>
<input type="text" value={name} onChange={(e)=>{ onChangeHandler("name",e.target.value)}} /> <br/>
<input type="email" value={email} onChange={(e)=>{ onChangeHandler("email",e.target.value)}} /> <br/>
<input type="submit" value="Submit" />
</form>
</div>
);
}
However, if you are having a complex form, it's hard to keep each value in state variables and then use validation on each field. For complex forms, it is recommended to use Formik that will do everything for you and you can use Yup validation package which is also supported by Formik that will allow you to add more than just simple validation.
2022
React suggests 3 approaches to handle forms:
Controlled components - In HTML, form elements such as <input>, <textarea>, and <select> typically maintain their own state and update it based on user input. In React, mutable state is typically kept in the state property of components, and only updated with setState(). We can combine the two by making the React state be the “single source of truth”. Then the React component that renders a form also controls what happens in that form on subsequent user input. An input form element whose value is controlled by React in this way is called a “controlled component”.
Uncontrolled components - It can sometimes be tedious to use controlled components, because you need to write an event handler for every way your data can change and pipe all of the input state through a React component. This can become particularly annoying when you are converting a preexisting codebase to React, or integrating a React application with a non-React library. In these situations, you might want to check out uncontrolled components, an alternative technique for implementing input forms.
Fully-Fledged Solutions - If you’re looking for a complete solution including validation, keeping track of the visited fields, and handling form submission, Formik is one of the popular choices. However, it is built on the same principles of controlled components and managing state — so don’t neglect to learn them.
All approaches are valid to react hooks too.
First consider which component better suit your needs, and use its appropriate validation solution.
We have plenty of options to validate the react js forms. Maybe the npm packages have some own limitations. Based up on your needs you can choose the right validator packages. I would like to recommend some, those are listed below.
react-form-input-validation
redux-form
If anybody knows a better solution than this, please put it on the comment section for other people references.
Cleaner way is to use joi-browser package. In the state you should have errors object that includes all the errors in the form. Initially it shoud be set to an empty object.
Create schema;
import Joi from "joi-browser";
schema = {
username: Joi.string()
.required()
.label("Username")
.email(),
password: Joi.string()
.required()
.label("Password")
.min(8)
.regex(/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).{8,1024}$/) //special/number/capital
};
Then validate the form with the schema:
validate = () => {
const options = { abortEarly: false };
const result = Joi.validate(this.state.data, this.schema, options);
console.log(data) // always analyze your data
if (!result.error) return null;
const errors = {};
for (let item of result.error.details) errors[item.path[0]] = item.message; //in details array, there are 2 properties,path and message.path is the name of the input, message is the error message for that input.
return errors;
};
Before submitting the form, check the form:
handleSubmit = e => {
e.preventDefault();
const errors = this.validate(); //will return an object
console.log(errors);
this.setState({ errors: errors || {} }); //in line 9 if we return {}, we dont need {} here
if (errors) return;
//so we dont need to call the server
alert("success");
//if there is no error call the server
this.dosubmit();
};
Might be late to answer - if you don't want to modify your current code a lot and still be able to have similar validation code all over your project, you may try this one too -
https://github.com/vishalvisd/react-validator.
Try powerform-react . It is based upon powerform which is a super portable Javascript form library. Once learnt, it can be used in any framework. It works even with vanilla Javascript.
Checkout this simple form that uses powerform-react
There is also a complex example.
Try this validation plugin in your form where you can add your custom validation rules.
Create a component FormValidation.js
import { useState } from "react";
const FormValidation = ({ validationRules, formInput }) => {
const [errors, setErrors] = useState(null);
const validation = () => {
// define a empty object to store errors.
let allErrors = {};
// Run loop on validation object
Object.keys(validationRules).forEach((name) => {
// name is the name of input field
const rulesArr = validationRules[name];
// Run loop on validation array applied on that input
rulesArr.forEach((rule) => {
// Skip if any error message is already stored in allErrors object
if (!allErrors[name]) {
let result;
// If rule is an array than it is a type of a function with parameter
switch (Array.isArray(rule)) {
case true: {
// take the function name and parameter value from rule array
const [functionName, paramValue] = rule;
// call validation function
result = functionName(formInput, name, paramValue);
break;
}
default:
// call validation function
result = rule(formInput, name);
break;
}
if (result) {
// append error in object
allErrors = { ...allErrors, ...result };
}
}
});
});
return allErrors;
};
const validate = () =>
new Promise((resolve, reject) => {
const errorObj = validation();
if (Object.keys(errorObj).length === 0) {
setErrors({});
resolve("Success");
} else {
setErrors(errorObj);
reject(Error("Some Error Occurred"));
}
});
return { validate, errors, setErrors };
};
export const required = (formInputs, inputName) =>
!formInputs[inputName] && { [inputName]: "This field is required" };
function emailPattern(email) {
return String(email)
.toLowerCase()
.match(
/^(([^<>()[\]\\.,;:\s#"]+(\.[^<>()[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
);
}
export const email = (formInputs, inputName) =>
!emailPattern(formInputs[inputName]) && {
[inputName]: "Please enter valid email",
};
export function passwordPattern(formInputs, inputName) {
const value = formInputs[inputName];
let error;
if (value.length < 8) {
error = "Your password must be at least 8 characters";
}
if (value.search(/[a-z]/i) < 0) {
error = "Your password must contain at least one letter.";
}
if (value.search(/[0-9]/) < 0) {
error = "Your password must contain at least one digit.";
}
if (value.search(/[ `!##$%^&*()_+\-=\[\]{};':"\\|,.<>\/?~]/) < 0) {
error = "Your password must contain at least one special character.";
}
return (
error && {
[inputName]: error,
}
);
}
export const maxLength = (formInputs, inputName, paramValue) =>
formInputs[inputName].length > paramValue && {
[inputName]: `Maximum characters are ${paramValue}`,
};
export const minLength = (formInputs, inputName, paramValue) =>
formInputs[inputName].length < paramValue && {
[inputName]: `Minimum characters are ${paramValue}`,
};
export default FormValidation;
I want to implement validations in my Login.js
import React, { useState } from "react";
import { Button, Form } from "react-bootstrap";
import FormValidation, {
required,
email,
passwordPattern,
} from "utils/FormValidation";
const Login = () => {
const [formInput, setFormInput] = useState({
email: "",
password: "",
});
const { validate, errors, setErrors } = FormValidation({
validationRules: {
email: [required, email],
password: [required, passwordPattern],
},
formInput,
});
const handleChange = (e) => {
setFormInput({ ...formInput, [e.target.name]: e.target.value });
};
const handleSubmit = (e) => {
e.preventDefault();
validate().then(() => {
//do whatever you want
console.log(formInput);
// you can set server error manually
setErrors({ email: "Email already exist" });
});
};
return (
<section className="gradient-form" style={{ backgroundColor: "#eee" }}>
<div className="container py-5 h-100">
<div className="row d-flex justify-content-center align-items-center h-100">
<div className="col-xl-10">
<div className="card rounded-3 text-black">
<div className="row g-0">
<div className="col-lg-6">
<div className="card-body p-md-5 mx-md-4">
<Form onSubmit={handleSubmit}>
<p>Please login to your account</p>
<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Control
type="text"
name="email"
placeholder="Enter email"
onChange={handleChange}
/>
{errors?.email && <span>{errors.email}</span>}
</Form.Group>
<Form.Group
className="mb-3"
controlId="formBasicPassword"
>
<Form.Control
type="password"
name="password"
placeholder="Password"
onChange={handleChange}
/>
{errors?.password && <span>{errors.password}</span>}
</Form.Group>
<Form.Group
className="mb-3"
controlId="formBasicCheckbox"
>
<Form.Check type="checkbox" label="Check me out" />
</Form.Group>
<div className="d-grid gap-2 mb-3">
<Button
variant="primary"
type="submit"
className="gradient-custom-2"
size="md"
>
Submit
</Button>
</div>
</Form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
);
};
export default Login;
Now you can pass any custom function in your validation array :
const { validate, errors, setErrors } = FormValidation({
validationRules: {
email: [required, email],
password: [required, passwordPattern, customFunciton],
},
formInput,
});
const customFunciton = (formInputs, inputName) => ({
[inputName]: `This error is from my custom function`,
});
I would like to suggest the following library, it is not react-specific. However, it provides an easy syntax and handy methods to run form validation. This is the react validation example from the library's documentation https://www.simple-body-validator.com/react/validation-quickstart

Categories

Resources