I've been working on form validation in my application, the user must provide a proper company name - full name - phone and email address. The weird behaviours I am facing is that :
1 - when I submit without filling out any input, I got the error message for the phone even though it is not the first place input. 2 - If a full out the form without the company name it, accept it too!
import { React, useState, useEffect } from "react";
/*
*****
*****
Import Showcase.scss -
*/
import "./Showcase.scss";
const Showacase = () => {
/*
*****
*****
Logic Goes Here
*/
//State Management
//Company State
*const [company, setCompany] = useState();
**const [companyValue, setCompanyValue] = useState();**
//name State
**const [name, setName] = useState();**
**const [nameValue, setNameValue] = useState();**
//Phone State
**const [phone, setPhone] = useState();
**const [phoneValue, setPhoneValue] = useState();****
//Email State
**const [email, setEmail] = useState();**
**const [emailValue, setEmailValue] = useState();**
//Hide Inputs
const [input, setInput] = useState(true);
// Message State
const [message, setMessage] = useState(true);
// SubMessage
const [subMessage, setSubMessage] = useState(true);
//InsertLine
const [line, setLine] = useState(false);
//Hide Button
const [btn, setBtn] = useState(true);
/* Validation State */
**const [companyValidate, setCompanyValidate] = useState(false);
**const [nameValidate, setNameValidate] = useState(false);**
**const [phoneValidation, setPhoneValidation] = useState(false);**
**const [emailValidate, setEmailValidate] = useState(false);*****
// OnSubmit
const onSubmit = (e) => {
e.preventDefault();
};
//onChange Company
const onChangeCompany = (e) => {
setCompany(e.target.value);
};
//OnClick
const onClick = (e) => {
// Company
**const reCompanyName = /^[a-zA-Z](?:[^0-9\s\x00-\x1F]|[ \t]){1,79}$/;**
//Name
**const reName = /[A-Za-z]{1,50}/;**
// Email Address
**const reEmail =
/^([a-zA-Z0-9_\-\.] )@([a-zA-Z0-9_\-\.] )\.([a-zA-Z]{2,5})$/;**
//Phone number
**const rePhone = /\ ?[0-9] ([0-9]|\/|\(|\)|\-| ){10,}/g;**
**if (!reCompanyName.test(company)) {
setCompanyValidate(true);
return;
} else {
setCompanyValidate(false);
}**
**if (!reName.test(name)) {
setNameValidate(true);
return;
} else {
setNameValidate(false);
}**
**if (!rePhone.test(phone)) {
setPhoneValidation(true);
return;
} else {
setPhoneValidation(false);
}**
**if (!reEmail.test(email)) {
setEmailValidate(true);
return;
} else {
setEmailValidate(false);
}**
//upComing Phone
**if (company === "" || phone === "" || email === "" || name === "") {
return;
} else {
/* setting the New Values */
setCompanyValue(company);
setNameValue(name);
setPhoneValue(phone);
setEmailValue(email);
/* Clearing the Inputs */
setCompany("");
setName("");
setPhone("");
setEmail("");
/* Logic of hidding Items */
setInput(false);
setMessage(false);
setSubMessage(false);
setLine(true);
setBtn(false);
/* Reset all options after submission after 5 seconds */
setTimeout(() => {
setInput(!false);
setMessage(!false);
setSubMessage(!false);
setLine(!true);
setBtn(!false);
setCompanyValidate(false);
setNameValidate(false);
setPhoneValidation(false);
setEmailValidate(false);
}, 5000);
}
};**
return (
<>
{/* Showcase Main */}
<div className="Showcase">
<div className="Container">
{/* Showcase Main / Applying the flex */}
<div className="Showcase__inside">
{/* Right Side / form and logic */}
<div className="Showcase__inside--left">
<div className="Showcase__inside--left--box">
{/* the Top Message */}
{message ? (
<h1>Find inbound call centers for your company</h1>
) : (
<h1>Thank you for your request!</h1>
)}
{/* the sub Message Message */}
{subMessage ? (
<p className="paragraphWilBeRemovedOnSmallScreen">
Use our AI and Big Data driven call center sourcing solution
</p>
) : (
<p className="paragraphAfterSubmission">
You’ve taken the first step. Our experts will get in touch
with you soon.
</p>
)}
{/* Inserting the Line */}
{line ? <hr></hr> : null}
<form onSubmit={onSubmit}>
{/* Company */}
<div className="Showcase__inside--left--box--form">
<label for="company">Company </label>
{input ? (
<div>
<input
required
value={company}
onChange={onChangeCompany}
type="text"
id="company"
placeholder="Company"
name="company"
/>
{companyValidate ? (
<div className="companyValidate">
<small>Please provide a valid company name</small>
</div>
) : (
""
)}
</div>
) : (
<p>{companyValue}</p>
)}
</div>
{/* Name */}
<div className="Showcase__inside--left--box--form">
<label for="Name">Name </label>
{input ? (
<div>
<input
required
onChange={(e) => setName(e.target.value)}
value={name}
type="text"
id="Name"
placeholder="Full name"
name="Name"
/>
{nameValidate ? (
<div className="nameValidate">
<small>Please Provide a valid Full Name</small>
</div>
) : (
""
)}
</div>
) : (
<p>{nameValue}</p>
)}
</div>
{/* Phone */}
<div className="Showcase__inside--left--box--form">
<label for="Phone">Phone </label>
{input ? (
<div>
<input
required
onChange={(e) => setPhone(e.target.value)}
value={phone}
type="number"
id="Phone"
placeholder=" 49"
name="phone"
/>
{phoneValidation ? (
<div className="phoneValidation">
<small>Please Provide a valid Phone Number</small>
</div>
) : (
""
)}
</div>
) : (
<p>{phoneValue}</p>
)}
</div>
{/* Email */}
<div className="Showcase__inside--left--box--form">
<label for="Email">Email </label>
{input ? (
<div>
<input
required
onChange={(e) => setEmail(e.target.value)}
value={email}
type="email"
id="Email"
placeholder="[email protected]"
name="email"
/>
{emailValidate ? (
<div className="EmailValidate">
<small>Please Provide a valid Email</small>
</div>
) : (
""
)}
</div>
) : (
<p>{emailValue}</p>
)}
</div>
{/* Submit */}
<div className="Showcase__inside--left--box--form">
<div className="Showcase__inside--left--box--form--submit">
{/* OnClick Method */}
{btn ? (
<button onClick={onClick} type="submit">
Get informed
</button>
) : null}
</div>
</div>
</form>
</div>
</div>
{/* Right SIDE %s */}
<div className="Showcase__inside--right">
<div>
<div>
<h1>Welcome to Europe’s largest call center database </h1>
</div>
<div className="Showcase__inside--right--per">
<div className="Showcase__inside--right--per--single">
<small>500 </small>
<h1>Tenders</h1>
</div>
<div className="Showcase__inside--right--per--single">
<small>200 </small>
<h1>Callcenter</h1>
</div>
<div className="Showcase__inside--right--per--single">
<small>375.000</small>
<h1>Agents available</h1>
</div>
<div className="Showcase__inside--right--per--single">
<small>85%</small>
<h1>Faster sourcing</h1>
</div>
</div>
</div>
</div>
{/* Right Ended %s */}
</div>
</div>
</div>
</>
);
};
export default Showacase;
CodePudding user response:
I know this may be a bit off topic, but I suggest you to use a pattern for form building and validations. Especially those multiple useState can be a bit cumbersome to use.
What I tend to use in my code is generally something like this:
let [model, setModel] = useState({firstName: '', lastName: '', ...})
let validations = {
firstName: ['required'],
...
}
return <Form model={model} setModel={setModel} validations={validations}>
<Field name="firstName" />
<Field name="lastName" />
<Submit>Send form</Submit>
</Form>
This is generally much shorter and helps consistency across your application.
If you want a sample implementation of form, fields, ..., you can use mine for instance:
import { cloneElement, useState } from "react";
export function Form({ model, setModel, validations, children, onSubmit, className }) {
let [errors, setErrors] = useState({});
function computeFieldErrors(fieldName, fieldValue) {
let fieldValidations = validations[fieldName] || [];
let fieldErrors = [];
for (let validation of fieldValidations) {
if (validation == "required") {
if (!fieldValue) fieldErrors.push("Must not be empty");
} else if (validation instanceof Array) {
if (validation[0] == "matches") {
if (fieldValue != model[validation[1]]) {
fieldErrors.push("Does not match " validation[1]);
}
} else {
alert("unknown validation: " validation[0]);
}
} else {
alert("unknown validation: " validation);
}
}
return fieldErrors;
}
function validateForm() {
let hasErrors = false;
let res = { ...errors };
for (let fieldName in model) {
let fieldErrors = computeFieldErrors(fieldName, model[fieldName]);
if (fieldErrors.length > 0) {
hasErrors = true;
res = { ...res, [fieldName]: fieldErrors };
}
}
setErrors(res);
if (!hasErrors) onSubmit(model);
}
function setData(fieldName, fieldValue) {
setModel({ ...model, ...{ [fieldName]: fieldValue } });
setErrors({ ...errors, [fieldName]: computeFieldErrors(fieldName, fieldValue) });
}
function fixChildren(nodes) {
return nodes.map((child, i) => {
if (child.type) {
if (child.type.name == "Field") {
return cloneElement(child, {
key: i,
data: model[child.props.name],
errors: errors[child.props.name],
setData: (value) => setData(child.props.name, value)
});
} else {
return cloneElement(child, {
key: i,
children: child.props.children
? fixChildren(child.props.children instanceof Array ? child.props.children : [child.props.children])
: null
});
}
}
else{
return child;
}
});
}
return (
<form
className={'form ' className}
onSubmit={(event) => {
event.preventDefault();
validateForm();
}}
>
{fixChildren(children)}
</form>
);
}
export function Field({ type, name, label, data, setData, errors, component, disabled, placeholder }) {
if (!component) {
if (type == "textarea") {
component = ({ data, setData }) => (
<textarea
id={name}
value={data}
onChange={(e) => setData(e.target.value)}
disabled={disabled}
defaultValue={data}
placeholder={placeholder}
></textarea>
);
} else {
component = ({ data, setData }) => (
<input
type={type || "text"}
id={name}
value={data}
placeholder={placeholder}
onChange={(e) => setData(e.target.value)}
disabled={disabled}
/>
);
}
}
return (
<div className={"field " ((errors || []).length > 0 ? "field--witherrors" : "")}>
<div className={"field__data"}>
<div className={"field__label"}>
<label htmlFor={name}>{label}</label>
</div>
<div className={"field__control"}>{component({ data, setData })}</div>
</div>
<div className={"field__errors"}>
<span>{(errors || []).join(", ")}</span>
</div>
</div>
);
}
export function Submit({children}) {
return <button type={"submit"}>{children}</button>;
}
CodePudding user response:
I would recommend using a library such as formik or react-hooks-form (from npm).
Forms and their validation are a non-trivial part of web applications, and although you can write it yourself, I would recommend getting a helping hand from a well-tested library.