MERN: best way to validate an Autocomplete control - reactjs

I'm working on user input validation, I'm having problems with the Autocomplete, so far I'm focus on evaluate if the associated TextField is empty, this is the code snippet:
<div className={clientMethodPaymentControlClasses}>
<label htmlFor="clientMethodPayment">Method of Payment *</label>
<Autocomplete
options={paymentMethods}
style={{ width: 300 }}
autoHighlight
renderInput={(params) => (
<TextField
id="clientMethodPayment"
{...params}
variant="outlined"
autocomplete="off"
ref={clientMethodPaymentRef}
/>
)}
/>
{!formInputsValidity.clientMethodPayment && (
<p>Please choose a method of payment</p>
)}
</div>
I try to catch the control's value using these lines:
const isEmpty = (value) => value.trim() === "";
....
const enteredClientMethodPaymentIsValid = !isEmpty(
enteredClientMethodPayment
);
During the execution I'm getting the error: Uncaught TypeError: value is undefined (related to const isEmpty).
This is the entire code of the component:
import { useRef, useState } from "react";
import TextField from "#material-ui/core/TextField";
import Autocomplete from "#material-ui/lab/Autocomplete";
import classes from "./Orderdetails.module.css";
const isEmpty = (value) => value.trim() === "";
const isNotNineChars = (value) => value.trim().length !== 9;
const paymentMethods = ["Cash", "Credit", "Crypto"];
const OrderDetails = (props) => {
const [formInputsValidity, setFormInputsValidity] = useState({
clientName: true,
clientCellPhone: true,
streetDeliveryAddress: true,
cityDeliveryAddress: true,
postalCodeDeliveryAddress: true,
ordersDeliveryAddress: true,
clientMethodPayment: true,
});
//estos objetos sirven para no capturar todos los keystrokes durante dataInput
const clientNameRef = useRef();
const clientCellPhoneRef = useRef();
const streetDeliveryAddressRef = useRef();
const cityDeliveryAddressRef = useRef();
const postalCodeDeliveryAddressRef = useRef();
const ordersDeliveryAddressRef = useRef();
const clientMethodPaymentRef = useRef();
const ConfirmHandler = (event) => {
event.preventDefault();
const enteredName = clientNameRef.current.value;
const enteredCellPhone = clientCellPhoneRef.current.value;
const enteredOrdersDeliveryAddress = ordersDeliveryAddressRef.current.value;
const enteredStreetDeliveryAddress = streetDeliveryAddressRef.current.value;
const enteredCityDeliveryAddress = cityDeliveryAddressRef.current.value;
const enteredPostalCodeDeliveryAddress =
postalCodeDeliveryAddressRef.current.value;
const enteredClientMethodPayment = clientMethodPaymentRef.current.value;
const enteredNameIsValid = !isEmpty(enteredName);
const enteredCellPhoneIsValid = !isNotNineChars(enteredCellPhone);
const enteredOrdersDeliveryAddressIsValid = !isEmpty(
enteredOrdersDeliveryAddress
);
const enteredStreetDeliveryAddressIsValid = !isEmpty(
enteredStreetDeliveryAddress
);
const enteredCityDeliveryAddressIsValid = !isEmpty(
enteredCityDeliveryAddress
);
const enteredPostalCodeDeliveryAddressIsValid = !isEmpty(
enteredPostalCodeDeliveryAddress
);
const enteredClientMethodPaymentIsValid = !isEmpty(
enteredClientMethodPayment
);
setFormInputsValidity({
clientName: enteredNameIsValid,
clientCellPhone: enteredCellPhoneIsValid,
ordersDeliveryAddress: enteredOrdersDeliveryAddressIsValid,
streetDeliveryAddress: enteredStreetDeliveryAddressIsValid,
cityDeliveryAddress: enteredCityDeliveryAddressIsValid,
postalCodeDeliveryAddress: enteredPostalCodeDeliveryAddressIsValid,
clientMethodPayment: enteredClientMethodPaymentIsValid,
});
const formIsValid =
enteredNameIsValid &&
enteredCellPhoneIsValid &&
enteredOrdersDeliveryAddressIsValid &&
enteredStreetDeliveryAddressIsValid &&
enteredCityDeliveryAddressIsValid &&
enteredPostalCodeDeliveryAddressIsValid &&
enteredClientMethodPayment;
if (!formIsValid) {
return;
}
props.onConfirm({
clientName: enteredName,
clientCellPhone: enteredCellPhone,
ordersDeliveryAddress: enteredOrdersDeliveryAddress,
streetDeliveryAddress: enteredStreetDeliveryAddress,
cityDeliveryAddress: enteredCityDeliveryAddress,
postalCodeDeliveryAddress: enteredPostalCodeDeliveryAddress,
clientMethodPayment: enteredClientMethodPayment,
});
};
const nameControlClasses = `${classes.control} ${
formInputsValidity.clientName ? "" : classes.invalid
}`;
const phoneControlClasses = `${classes.control} ${
formInputsValidity.clientCellPhone ? "" : classes.invalid
}`;
const delivAddressControlClasses = `${classes.control} ${
formInputsValidity.ordersDeliveryAddress ? "" : classes.invalid
}`;
const cityDeliveryAddressControlClasses = `${classes.control} ${
formInputsValidity.cityDeliveryAddress ? "" : classes.invalid
}`;
const streetDeliveryAddressControlClasses = `${classes.control} ${
formInputsValidity.streetDeliveryAddress ? "" : classes.invalid
}`;
const postalCodeDeliveryAddressControlClasses = `${classes.control} ${
formInputsValidity.postalCodeDeliveryAddress ? "" : classes.invalid
}`;
const clientMethodPaymentControlClasses = `${classes.control} ${
formInputsValidity.clientMethodPayment ? "" : classes.invalid
}`;
return (
<form className={classes.form} onSubmit={ConfirmHandler}>
<div className={nameControlClasses}>
<label htmlFor="clientName">Client's Name</label>
<input
type="text"
autoComplete="off"
id="clientName"
ref={clientNameRef}
/>
{!formInputsValidity.clientName && <p>Please Enter a valid Name</p>}
</div>
<div className={phoneControlClasses}>
<label htmlFor="clientCellPhone">Client's Cell Phone Number</label>
<input
type="text"
id="clientCellPhone"
autocomplete="off"
ref={clientCellPhoneRef}
/>
{!formInputsValidity.clientCellPhone && (
<p>Please Enter a 8 digits numbers</p>
)}
</div>
<div className={delivAddressControlClasses}>
<label htmlFor="ordersDeliveryAddress">Delivery Address *</label>
<input
type="text"
id="ordersDeliveryAddress"
autocomplete="off"
ref={ordersDeliveryAddressRef}
/>
{!formInputsValidity.ordersDeliveryAddress && (
<p>Please Enter a valid address</p>
)}
</div>
<div className={cityDeliveryAddressControlClasses}>
<label htmlFor="cityDeliveryAddress">City Delivery Address *</label>
<input
type="text"
id="cityDeliveryAddress"
autocomplete="off"
ref={cityDeliveryAddressRef}
/>
{!formInputsValidity.cityDeliveryAddress && (
<p>Please Enter a valid city name</p>
)}
</div>
<div className={streetDeliveryAddressControlClasses}>
<label htmlFor="streetDeliveryAddress">Street Delivery Address *</label>
<input
type="text"
id="streetDeliveryAddress"
autocomplete="off"
ref={streetDeliveryAddressRef}
/>
{!formInputsValidity.streetDeliveryAddress && (
<p>Please Enter a valid street name</p>
)}
</div>
<div className={postalCodeDeliveryAddressControlClasses}>
<label htmlFor="postalCodeDeliveryAddress">
Postal Code Delivery Address *
</label>
<input
type="text"
id="postalCodeDeliveryAddress"
autocomplete="off"
ref={postalCodeDeliveryAddressRef}
/>
{!formInputsValidity.postalCodeDeliveryAddress && (
<p>Please Enter a valid Postal Code</p>
)}
</div>
<div className={clientMethodPaymentControlClasses}>
<label htmlFor="clientMethodPayment">Method of Payment *</label>
<Autocomplete
options={paymentMethods}
style={{ width: 300 }}
autoHighlight
renderInput={(params) => (
<TextField
id="clientMethodPayment"
{...params}
variant="outlined"
autocomplete="off"
ref={clientMethodPaymentRef}
/>
)}
/>
{!formInputsValidity.clientMethodPayment && (
<p>Please choose a method of payment</p>
)}
</div>
<div className={classes.actions}>
<button type="button" onClick={props.onCancel}>
Close
</button>
<button>Confirm Order</button>
</div>
</form>
);
};
export default OrderDetails;
My questions are:
is it a good approach trying to validate the related Textfield of Autocomplete?
what should be the best way to validate if the Autocomplete control is Empty?
Thanks in advance.

Related

How to Validate Minimum Age Greater & Equal to 18 Reactjs

For the SignUp page I need to validate age is equal to or greater than 18. I have attempted using similar examples but all require me to install a dependency. I am looking for a way to achieve the desired results through React. My code is as follows
signup.jsx
import React from "react";
import { useState, useRef } from "react";
import { BsFillInfoCircleFill } from "react-icons/bs";
import Tooltip from "react-bootstrap/Tooltip";
import OverlayTrigger from "react-bootstrap/OverlayTrigger";
import { Link } from "react-router-dom";
import Alert from 'react-bootstrap/Alert'
import { UserAuth } from "../../AuthContext";
const Password = (props) =>
{
const [passwordShown, setPasswordShown] = useState(false);
const togglePassword = () => {
setPasswordShown(!passwordShown);
}
return(
<div className="input-group w-75 mb-5">
<input
type= {passwordShown ? 'text' : 'password'}
ref = {props.myRef}
className="form-control shadow-none"
placeholder="PSU1>OSU!"
aria-describedby="button-addon2"
></input>
<button onClick={togglePassword}>Show Password</button>
</div>
);
}
const SignUpPopup = (props) => {
//input fields
const firstName = useRef("");
const lastName = useRef("");
const email = useRef("");
const DOB = useRef("");
const password = useRef("");
const passwordConfirm = useRef("");
const [checked1, setChecked1] = useState(false);
const [checked2, setChecked2] = useState(false);
var errorMessage = ""
//change handlers
const handleChange1 = () => { setChecked1(!checked1) } ;
const handleChange2 = () => { setChecked2(!checked2) } ;
const [error, setError] = useState("");
const {createUser} = UserAuth();
//IMPROVE THE CHECKING OF THE FORM
function checkSignUp(){
var success = true
if (firstName.current.value === ""){
success = false
errorMessage += "Invalid first name\n"
}
if (lastName.current.value === ""){
success = false
errorMessage += "Invalid last name\n"
}
if (email.current.value === ""){
success = false
errorMessage += "Invalid email\n"
}
if (password.current.value === "" ){
success = false
errorMessage += "Invalid password\n"
}
if (!(passwordConfirm.current.value === password.current.value ) ){
success = false
errorMessage += "Passwords do not match\n"
}
return success;
}
async function addUserToDatabase(uid){
fetch("URL",{
method: "POST",
headers: { "Content-Type": "application/json"},
body: uid
})
}
async function handleSignup() {
setError("")
//if res == true, success, else failure and trigger alert
var res = checkSignUp();
if(res){
//authenticate
try{
await createUser(email.current.value, password.current.value);
const {user} = UserAuth();
addUserToDatabase(user.uid);
props.handleClose();
props.signupNextFunc();
}
catch(e){
errorMessage += "Invalid email or password"
setError(errorMessage)
}
}
}
const changeToLogin = ()=>{
props.handleClose()
props.loginFunc()
}
return (
<div className="popup-box">
<div className="box">
<div className="upperwrapper">
<span className="close-icon" onClick={props.handleClose}>
x
<input
type="text"
ref={firstName}
className="form-control shadow-none"
placeholder="Ben"
aria-describedby="button-addon2"
></input>
</div>
{/* LAST NAME INPUT */}
<p style={{ fontSize: "20px", marginTop: "15px" }}>
Last Name<span className="required-field"></span>
</p>
<div className="input-group w-75 mb-5">
<input
type="text"
ref = {lastName}
className="form-control shadow-none"
placeholder="Dover"
aria-describedby="button-addon2"
></input>
</div>
{/* EMAIL INPUT */}
<p style={{ fontSize: "20px", marginTop: "45px" }}>
Email<span className="required-field"></span>
</p>
<div className="input-group w-75 mb-5">
<input
type="text"
ref = {email}
className="form-control shadow-none"
placeholder="bendover#email.com"
aria-describedby="button-addon2"
></input>
</div>
<div className="d-flex bd-highlight mb-3 example-parent">
<p style={{ fontSize: "20px", marginTop: "10px" }}>
Date of Birth<span className="required-field"></span>
</p>
<div style={{ display: 'block', marginLeft: "-3px", marginTop: "-8px" }}
className="align-self-center p-2 bd-highlight col-example">
<OverlayTrigger
delay={{ hide: 450, show: 300 }}
overlay={(props) => (
<Tooltip {...props}>
Please provide your date of birth to validate...
</Tooltip>
)}
placement="right"
>
<div><BsFillInfoCircleFill /></div>
</OverlayTrigger>
</div>
</div>
<div className="input-group w-75 mb-5">
<input
type="date"
ref={DOB}
className="form-control shadow-none"
placeholder="mm/dd/yyyy"
aria-describedby="button-addon2"
></input>
</div>
)
};
export default SignUpPopup;
Any help or guidance to the right path is greatly appreciated!
You can validate age on onChange of input
const onChange = (e) => {
const currentYear = new Date().getFullYear();
const year = e.target.value.split("-")[0];
const age = currentYear - year;
if (age < 18) setError("Invalid age");
}
<input
type="date"
className="form-control shadow-none"
placeholder="mm/dd/yyyy"
aria-describedby="button-addon2"
onChange={onChange}
/>

Im facing error in firstname ,lastname required in my code. It is not showing those errors

Here for email, password and confirm password error messages are showing but for firstname, phone number and lastname the error is not showing. How can I find out what that error is?
For email when I click on that field and do not give any value, it is showing an error and the same thing for firstname.
import React from "react";
import { useState } from "react";
const emailValidator = /^(([^<>()\[\]\\.,;:\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,}))$/;
function Register(props) {
const [state, setState] = useState({
email: "",
emailAddressError: "",
firstName: "",
firstNameError: ""
});
const handleChange = (event) => {
const { name, value } = event.target;
setState((prev) => ({ ...prev, [name]: value }));
return;
};
const handleBlur = (event) => {
const { name } = event.target;
validateField(name);
return;
};
const handleSubmit = (e) => {
e.preventDefault();
let formFileds = ["email", "firstName"];
let isValid = true;
formFileds.forEach((field) => {
isValid = validateField(field) && isValid;
});
if (isValid) setState((prev) => ({ ...prev, isFormSubmitted: true }));
else setState((prev) => ({ ...prev, isFormSubmitted: false }));
return state.isFormSubmitted;
};
const validateField = (name) => {
let isValid = false;
if (name === "email") isValid = validateemail();
else if (name === "firstName") isValid = validatefirstName();
return isValid;
};
const validatefirstName = () => {
let firstNameError = "";
const value = state.firstName;
if (value.trim() === "") firstNameError = "First Name is required";
setState((prev) => ({ ...prev, firstNameError }));
return firstNameError === "";
};
const validateemail = () => {
let emailAddressError = "";
const value = state.email;
if (value === "") emailAddressError = "Email Address is required";
else if (!emailValidator.test(value))
emailAddressError = "Email is not valid";
setState((prev) => ({ ...prev, emailAddressError }));
return emailAddressError === "";
};
return (
<div id="__next">
<div class="no-gutters row" style={{ height: "100vh" }}>
<div class="d-flex flex-column justify-content-center align-items-center h-100 col-12 col-md-6">
<div class="container">
<div class="d-flex justify-content-center row">
<div class="col-auto col-lg-8">
<h5 class="fw-bold mb-5">Sign Up</h5>
<form class="w-100">
<div class="d-flex form-group">
<div class="flex-fill mr-5">
<span style={{ color: "red" }}> *</span>
<label for="exampleEmail" class="fw-bold">
First Name
</label>
<input
name="firstName"
value={state.firstName}
onChange={handleChange}
maxLength="20"
class="form-control"
placeholder="First Name"
/>
</div>
{state.firstNameError && (
<div className="errorMsg" style={{ color: "red" }}>
{state.firstNameError}
</div>
)}
</div>
<div class="form-group">
<span style={{ color: "red" }}> *</span>
<label for="exampleEmail" class="fw-bold">
Email
</label>
<input
name="email"
class="form-control"
value={state.email}
onChange={handleChange}
placeholder="Email"
onBlur={handleBlur}
autoComplete="off"
/>
</div>
{state.emailAddressError && (
<div className="errorMsg" style={{ color: "red" }}>
{state.emailAddressError}
</div>
)}
<div class="d-flex justify-content-between align-items-center mt-5">
<a
href="/login"
style={{ textDecoration: "none", color: "#bd744c" }}
>
{" "}
</a>
<button
class="btn "
style={{ backgroundColor: "#bd744c", color: "white" }}
onSubmit={handleSubmit}
>
<b>SIGN UP</b>
</button>
</div>
</form>
<br />
</div>
</div>
</div>
</div>
<div class="d-none d-md-inline-block h-100 Register_backgroundImage__2j-eI col-sm-6"></div>
</div>
</div>
);
}
// export default Register;
export default Register;
You forgot to call onBlur={handleBlur} in firstName and I have made small changes in your code:
Now it will show errors when you click on submit.

react simple keyboard not able to type in multiple input

I have following code of Calculator.jsx where everything looks fine.The main thing I want to achieve is keyboard to displayed only on input click which is done but the keyboard does not seem to type though the following code looks fine. Are there any other way to show/hide keyboard only on input click as well as make keyboard be able to type. My code for Calculator.jsx is
Calculator.jsx
import React, { useState, useRef, useEffect } from 'react';
import './Calculator.css'
import { Link } from 'react-router-dom';
import Keyboard from "react-simple-keyboard";
import "react-simple-keyboard/build/css/index.css";
const Calculator = () => {
const [inputs, setInputs] = useState({});
const [layoutName, setLayoutName] = useState("default");
const [inputName, setInputName] = useState("default");
const keyboard = useRef();
const [keyboardVisibility, setKeyboardVisibility] = useState(false);
useEffect(() => {
function clickHanlder(e) {
if (
!(e.target.nodeName === "INPUT") &&
!e.target.classList.contains("hg-button") &&
!e.target.classList.contains("hg-row")
) {
setKeyboardVisibility(false);
}
}
window.addEventListener("click", clickHanlder);
return window.removeEventListener("click", clickHanlder, true);
}, []);
const onChangeAll = inputs => {
setInputs({ ...inputs });
console.log("Inputs changed", inputs);
};
const handleShift = () => {
const newLayoutName = layoutName === "default" ? "shift" : "default";
setLayoutName(newLayoutName);
};
const onKeyPress = button => {
console.log("Button pressed", button);
if (button === "{shift}" || button === "{lock}") handleShift();
};
const onChangeInput = event => {
const inputVal = event.target.value;
setInputs({
...inputs,
[inputName]: inputVal
});
keyboard.current.setInput(inputVal);
};
const getInputValue = inputName => {
return inputs[inputName] || "";
};
return (
<div>
<div className="bg">
<div className="deposit">
<div className="header">
<h1>Deposit Calculator</h1>
<div className="form">
<form className="calculator">
<div className="form-group">
<label for="depositAmount">Deposit Amount:</label>
<span className="rupees">Rs</span>
<input className="IInput"
type="text"
name='depositAmount'
placeholder='0'
value={getInputValue("depositAmount")}
onChange={onChangeInput}
onFocus={() => {
setKeyboardVisibility(true);
setInputName("depositAmount")
}}
/>
</div>
<div className="form-group">
<label for="interestRate">Interest Rate:</label>
<input className= "IIinput"
type="text"
name='Interest'
placeholder='0'
value={getInputValue("interestRate")}
onChange={onChangeInput}
onFocus={() => {
setKeyboardVisibility(true);
setInputName("interestRate")
}}
/>
<span className= "percent">%</span>
</div>
<div class="form-group">
<label for="Tenure">Tenure:</label>
<input className="Input"
type='number'
min='1'
max='5'
name='tenure'
placeholder='1 year'
value={getInputValue("tenure")}
onChange={onChangeInput}
onFocus={() => {
setKeyboardVisibility(true);
setInputName("tenure")
}}
/>
</div>
{ keyboardVisibility && (
<Keyboard
keyboardRef={(r) => (keyboard.current = r)}
layoutName={layoutName}
onChange={onChangeAll}
onKeyPress={onKeyPress}
/>
)}
</form>
<button className="calculate">Calculate
</button>
</div>
<div className="given">
<p >
Total Deposit: Rs 0
</p>
<p>
Interest: Rs 0
</p>
<p>
Maturity Amount: Rs 0
</p>
</div>
</div>
</div>
</div>
<Link to="/">
<button className="Back">
<i class="fas fa-angle-double-left"></i>
</button>
</Link>
</div>
);
};
export default Calculator;
You are setting the inputs state by spreading input string from keyboard onChangeAll into an object setInputs({ ...inputs }). If I enter ab it will set as {0: "a", 1:"b"}.
Update the onChange prop in Keyboard to onChangeAll and pass inputName prop with your inputName state value. Read react-simple-keyboard DOCS.
onChangeAll
const onChangeAll = (inputs) => {
console.log("Inputs changed", inputs);
setInputs(inputs);
};
Keyboard
{keyboardVisibility && (
<Keyboard
keyboardRef={(r) => (keyboard.current = r)}
layoutName={layoutName}
onChangeAll={onChangeAll}
onKeyPress={onKeyPress}
inputName={inputName}
/>
)}
CodeSandbox link

lifting state up from child to parent, resets my parents states

when I lift the state up to a parent it resets all my states in the parent component.
Parent Component
const [validName, setValidName] = useState(false);
const [validAddress, setValidAddress] = useState(false);
const [validPostal, setValidPostal] = useState(false);
const [validPhone, setValidPhone] = useState(false);
const [validEmail, setValidEmail] = useState(false);
const [validForm, setValidForm] = useState(false);
const isDisabled = (pWidth, pLength) => {
console.log("pWidth: " + pWidth);
console.log("pLength: " + pLength);
setSheetSize(pWidth, pLength);
console.log("in isDisabled!");
console.log(validName);
console.log(validAddress);
console.log(validPostal);
console.log(validPhone);
console.log(validEmail);
validateForm();
};
const setSheetSize = (width, length) => {
console.log("setSheetSize width: " + width);
console.log("setSheetSize length: " + length);
setLength(length);
setWidth(width);
};
const setRadiusSize = (radius) => {
setRadius(radius);
};
const [selectedOption, setSelectOption] = useState(
<SheetForm isDisabled={isDisabled} />
);
return (
<Col md={3}>
<div className="form-check mt-4">
<input
className="form-check-input"
type="radio"
name="cakeType"
id="sheet"
value="sheet"
checked={checkOption === "sheet"}
onClick={(e) => {
setCheckOption(e.target.value);
setSelectOption(<SheetForm isDisabled={isDisabled} />);
}}
/>
<label className="form-check-label" htmlFor="sheet">
Sheet Cake
</label>
</div>
</Col>
)
Child Component
import { useState } from "react";
const SheetForm = (props) => {
const [innerLength, setInnerLength] = useState();
const [innerWidth, setInnerWidth] = useState();
let isLengthGood = false;
let isWidthGood = false;
function validateSheetSize() {
if (innerLength >= 30 && innerLength <= 60) {
document.getElementById("length").classList.add("is-valid");
document.getElementById("length").classList.remove("is-invalid");
isLengthGood = true;
} else {
document.getElementById("length").classList.remove("is-valid");
document.getElementById("length").classList.add("is-invalid");
}
if (innerWidth >= 30 && innerWidth <= 45) {
document.getElementById("width").classList.add("is-valid");
document.getElementById("width").classList.remove("is-invalid");
isWidthGood = true;
} else {
document.getElementById("width").classList.remove("is-valid");
document.getElementById("width").classList.add("is-invalid");
}
if (isLengthGood && isWidthGood) {
console.log("everything good");
props.isDisabled(innerWidth, innerLength);
}
}
return (
<div id="sheetOption" className="mt-4">
<div className="input-group">
<span className="input-group-text">Sheet Size</span>
<input
onBlur={validateSheetSize}
id="length"
type="text"
aria-label="length"
className="form-control"
placeholder="min 30 max 60"
name="length"
min="30"
max="60"
required
onChange={(e) => {
setInnerLength(e.target.value);
}}
/>
<span className="input-group-text" id="basic-addon1">
L (cm)
</span>
<div className="valid-feedback">Looks good!</div>
<div className="invalid-feedback">
Length must be between 30cm and 60cm!
</div>
</div>
<div className="input-group">
<span className="input-group-text">Sheet Size</span>
<input
onBlur={validateSheetSize}
id="width"
type="text"
aria-label="width"
className="form-control"
placeholder="min 30 max 45"
name="width"
min="30"
max="45"
required
onChange={(e) => {
setInnerWidth(e.target.value);
}}
/>
<span className="input-group-text" id="basic-addon1">
W (cm)
</span>
<div className="valid-feedback">Looks good!</div>
<div className="invalid-feedback">
Width must be between 30cm and 45cm!
</div>
</div>
</div>
);
};
export default SheetForm;
I can lift the state back up to the parent and get the correct values, but when I check the states for validName, validAddress, validPostal, etc...
they all come back to the original setState of false.

clear controlled components in a form using react after clicking submit button

I have created a form to enter name, email, website and message. After entering the details using submit button I want to reset all the fields. I don't know how to use control component. Please help..
This is how I enter Input fields.
export default ({
noLabels = false,
margin = "",
small = false,
blueButton = false,
buttonLabel = null,
quickContact = false,
subject = "New message from website",
}) => {
const [name, setName] = useState(
process.env.NODE_ENV === "development" ? "abc" : ""
)
const [email, setEmail] = useState(
process.env.NODE_ENV === "development" ? "abc#blabla.io" : ""
)
const [phone, setPhone] = useState(
process.env.NODE_ENV === "development" ? "Phone" : ""
)
const [country, setCountry] = useState(
process.env.NODE_ENV === "development" ? "Country" : ""
)
const [message, setMessage] = useState(
process.env.NODE_ENV === "development" ? "Message" : ""
)
const [website, setWebsite] = useState(
process.env.NODE_ENV === "development" ? "abc.io" : ""
)
const handleSubmit = e => {
e.preventDefault()
var formData = new FormData()
formData.set("name", name)
formData.set("email", email)
formData.set("phone", phone)
formData.set("country", country)
formData.set("message", message)
formData.set("website", website)
formData.set("subject", subject)
api
.contact(formData)
.then(res => {
if (typeof window !== "undefined") {
const uikit = require("uikit")
uikit
.toggle(
document.getElementById(
quickContact
? "form_success_message_quick"
: "form_success_message"
)
)
.toggle()
}
})
.catch(error => {
if (typeof window !== "undefined") {
const uikit = require("uikit")
uikit
.toggle(
document.getElementById(
quickContact ? "form_error_message_quick" :
"form_error_message"
)
)
.toggle()
}
})
}
return (
<form
action="/send-mail.php"
className="uk-form contact_form"
method="post"
onSubmit={handleSubmit}
>
<div
className="uk-alert-primary contact-form-success-quick"
data-uk-alert
id={
quickContact ? "form_success_message_quick" :
"form_success_message"
}
hidden
>
<a className="uk-alert-close" data-uk-close></a>
<p>
Thank you for contacting us. We will get in touch with you
shortly.
</p>
</div>
<div
className="uk-alert-primary contact-form-error-quick"
data-uk-alert
id={quickContact ? "form_error_message_quick" : "form_error_message"}
hidden>
<a className="uk-alert-close" data-uk-close></a>
<p>
Thank you for contacting us. We will get in touch with you shortly.
</p>
</div>
<div
className={`uk-grid ${
small || quickContact ? "uk-grid-small" : "uk-grid-medium"
}`}
>
<div className={quickContact ? "uk-width-1-3#s" : "uk-width-1-2#s"}>
<InputField
label="Name *"
value={name}
setValue={setName}
noLabels={noLabels}
margin={margin}
small={small}
/>
</div>
<div className={quickContact ? "uk-width-1-3#s" : "uk-width-1-2#s"}>
<InputField
label="Email *"
value={email}
setValue={setEmail}
noLabels={noLabels}
margin={margin}
small={small}
/>
</div>
{quickContact && (
<div className="uk-width-1-3#s">
<InputField
label="Website"
value={website}
setValue={setWebsite}
noLabels={noLabels}
margin={margin}
small={small}
/>
</div>
)}
{!quickContact && (
<div className="uk-width-1-2#s">
<InputField
label="Phone number *"
value={phone}
setValue={setPhone}
noLabels={noLabels}
margin={margin}
small={small}
/>
</div>
)}
{!quickContact && (
<div className="uk-width-1-2#s">
<InputField
label="Website"
value={website}
setValue={setWebsite}
noLabels={noLabels}
margin={margin}
small={small}
/>
</div>
)}
<div className="uk-width-1-1">
<InputField
label="Message *"
value={message}
setValue={setMessage}
textArea
noLabels={noLabels}
margin={margin}
small={small}
/>
</div>
<div className="uk-width-1-1 uk-text-center">
<button
type="submit"
className={`uk-button ${blueButton ? "blue" : "purple"}`}
value="Submit"
name="submit"
>
{buttonLabel ? buttonLabel : "Submit"}
</button>
</div>
</div>
</form>
)
}
const InputField = ({
noLabels,
value,
setValue,
label,
textArea = false,
margin,
small,
}) => {
<>
{textArea ? (
<textarea
placeholder={label}
className={`uk-textarea custom-margin-${
margin ? margin + "-" : ""
}bottom ${!small && "uk-form-large"}`}
cols="30"
rows="6"
required
value={value}
onChange={e => setValue(e.target.value)}
></textarea>
) : (
<input
type="text"
className={`uk-input custom-margin-${
margin ? margin + "-" : ""
}bottom ${!small && "uk-form-large"}`}
placeholder={label}
required
value={value}
onChange={e => setValue(e.target.value)}
/>
)}
</>
I want to reset this code using "e.target.reset()" if possible.
Also the method how to use "setValue" would be great help.
Use a single useState hook to hold the values for the form to make it easier to set them all in a single call.
Don't manipulate the DOM directly—instead use state + React to declare the desired output given the current state.
Refactor multiple conditionals that are addressing the same concern into a single conditional (re: process.env.NODE_ENV)
Pass a callback to the state setter to modify the existing props rather than having to explicitly write the function to modify each input's value manually.
const devValues = {
name: "abc",
email: "abc#blabla.io",
phone: "Phone",
country: "Country",
message: "Message",
website: "abc.io",
}
const defaultValues = {
name: "",
email: "",
phone: "",
country: "",
message: "",
website: "",
}
export default ({
noLabels = false,
margin = "",
small = false,
blueButton = false,
buttonLabel = null,
quickContact = false,
subject = "New message from website",
}) => {
const [message, setMessage] = useState(null)
const [inputValues, setInputValues] = useState(
process.env.NODE_ENV === "development" ? devValues : defaultValues
)
const handleSubmit = (e) => {
e.preventDefault()
var formData = new FormData()
Object.entries(inputValues).forEach(([key, value]) => {
formData.set(key, value)
})
api
.contact(formData)
.then((res) => {
setMessage(
quickContact ? "form_success_message_quick" : "form_success_message"
)
// clear the input values here
setInputValues(defaultValues)
})
.catch((error) => {
setMessage(
quickContact ? "form_error_message_quick" : "form_error_message"
)
})
}
return (
<form
action="/send-mail.php"
className="uk-form contact_form"
method="post"
onSubmit={handleSubmit}
>
{message && (
<div
className={
message.startsWith("form_success_message")
? "uk-alert-primary contact-form-success-quick"
: "uk-alert-primary contact-form-error-quick"
}
data-uk-alert
>
<a className="uk-alert-close" data-uk-close></a>
<p>
Thank you for contacting us. We will get in touch with you shortly.
</p>
</div>
)}
<div
className={`uk-grid ${
small || quickContact ? "uk-grid-small" : "uk-grid-medium"
}`}
>
<div className={quickContact ? "uk-width-1-3#s" : "uk-width-1-2#s"}>
<InputField
label="Name *"
name="name"
value={inputValues.name}
setValue={setInputValues}
noLabels={noLabels}
margin={margin}
small={small}
/>
</div>
<div className={quickContact ? "uk-width-1-3#s" : "uk-width-1-2#s"}>
<InputField
label="Email *"
name="email"
value={inputValues.email}
setValue={setInputValues}
noLabels={noLabels}
margin={margin}
small={small}
/>
</div>
{quickContact && (
<div className="uk-width-1-3#s">
<InputField
label="Website"
name="website"
value={inputValues.website}
setValue={setInputValues}
noLabels={noLabels}
margin={margin}
small={small}
/>
</div>
)}
{!quickContact && (
<div className="uk-width-1-2#s">
<InputField
label="Phone number *"
name="phone"
value={inputValues.phone}
setValue={setInputValues}
noLabels={noLabels}
margin={margin}
small={small}
/>
</div>
)}
{!quickContact && (
<div className="uk-width-1-2#s">
<InputField
label="Website"
name="website"
value={inputValues.website}
setValue={setInputValues}
noLabels={noLabels}
margin={margin}
small={small}
/>
</div>
)}
<div className="uk-width-1-1">
<InputField
label="Message *"
name="message"
value={inputValues.message}
setValue={setInputValues}
textArea
noLabels={noLabels}
margin={margin}
small={small}
/>
</div>
<div className="uk-width-1-1 uk-text-center">
<button
type="submit"
className={`uk-button ${blueButton ? "blue" : "purple"}`}
value="Submit"
name="submit"
>
{buttonLabel ? buttonLabel : "Submit"}
</button>
</div>
</div>
</form>
)
}
const InputField = ({
name,
value,
setValue,
label,
textArea = false,
margin,
small,
}) => {
const onChange = (e) => {
const value = e.target.value
setValue((prev) => ({ ...prev, [name]: value }))
}
return textArea ? (
<textarea
placeholder={label}
className={`uk-textarea custom-margin-${
margin ? margin + "-" : ""
}bottom ${!small && "uk-form-large"}`}
cols="30"
rows="6"
required
value={value}
onChange={onChange}
/>
) : (
<input
type="text"
className={`uk-input custom-margin-${margin ? margin + "-" : ""}bottom ${
!small && "uk-form-large"
}`}
placeholder={label}
required
value={value}
onChange={onChange}
/>
)
}
Among the correct answer and especially the recommendations of #coreyward I want to add another approach that may help you or other users in the same trouble.
You can also use a useRef hook and ref, to your form tag and simply clear it with the native reset() function:
export default ({
noLabels = false,
margin = "",
small = false,
blueButton = false,
buttonLabel = null,
quickContact = false,
subject = "New message from website",
}) => {
const mailForm = useRef(null)
//... more code
}
return (
<form
action="/send-mail.php"
className="uk-form contact_form"
method="post"
onSubmit={handleSubmit}
ref={mailForm}
>
)
Then, in your submit function you have exposed a mailForm.current as your form. You can simply:
const handleSubmit = (e) => {
e.preventDefault()
var formData = new FormData()
Object.entries(inputValues).forEach(([key, value]) => {
formData.set(key, value)
})
api
.contact(formData)
.then((res) => {
setMessage(
quickContact ? "form_success_message_quick" : "form_success_message"
)
// clear the input values here
mailForm.curent.reset();
})
.catch((error) => {
setMessage(
quickContact ? "form_error_message_quick" : "form_error_message"
)
})
}

Resources