I am passing placeholder text as a prop to the <FormField/> from the <CreatePost/>. I need to show the placeholder text in the form but it is not showing but when i console.log in the <FormField/> placeholder text is showing in the console with no errors but not in the input tag.
passing props to the <FormField/> from <CreatePost/>
function CreatePost() {
const navigate = useNavigate();
const [form, setForm] = useState({
name: ' ',
photo: ' ',
prompt: ' ',
});
const [generatingImg, setGeneratingImg] = useState(false);
const [loading, setLoading] = useState(false);
const handleSubmit = () => {};
const handleChange = e => {};
const handleSurpriseMe = () => {};
return (
<section className='max-w-7xl mx-auto'>
<form className='mt-16 max-w-3xl' onSubmit={handleSubmit}>
<div className='flex flex-col gap-5'>
<FormField
LabelName='Your name'
type='text'
name='name'
placeholder='John Doe'
value={form.name}
handleChange={handleChange}
/>
<FormField
LabelName='Prompt'
type='text'
name='prompt'
placeholder='Spongebob Squarepants in the Blair Witch Project'
value={form.prompt}
isSurpriseMe
handleChange={handleChange}
defaultValue='Initial value'
handleSurpriseMe={handleSurpriseMe}
/>
</div>
</form>
</section>
);
}
FormField.jsx
function FormField({
LabelName,
type,
name,
placeholder,
value,
handleChange,
isSurpriseMe,
handleSurpriseMe,
}) {
console.log(placeholder);
return (
<div>
<div className='flex items-center mb-2 gap-2'>
<label
htmlFor={name}
className='block text-sm font-medium text-gray-900'
>
{LabelName}
</label>
{isSurpriseMe && (
<button
className='font-semibold py-1 px-2 text-xs bg-[#ECECF1] hover:bg-[#d7d7e7] rounded-[5px] text-black'
type='button'
onClick={handleSurpriseMe}
>
Surprise me
</button>
)}
</div>
<input
type={type}
id={name}
name={name}
placeholder={placeholder}
value={value}
onChange={handleChange}
required
className='bg-gray-50 border border-gray-300
text-gray-900 text-sm rounded-lg focus:ring-[#4649ff]
focus:border-[#4649ff] ouline-none block w-full p-3
'
/>
</div>
);
}
Results showing in the console.log
John Doe
VM256 installHook.js:1861 John Doe
FormField.jsx:13 Spongebob Squarepants in the Blair Witch Project
VM256 installHook.js:1861 Spongebob Squarepants in the Blair Witch Project
When you press space in an HTML input field, the placeholder disappears.
So the same is happening in the above case. You are setting the initial value to a string with a space rather than an empty string. Setting the state to an empty string would get your job done
const [form, setForm] = useState({
name: '', // this is an empty string
photo: ' ',// this is a string with a space
prompt: ' ',
});
Related
So I'm working on a booking system project and I have a form that the user can fill out, with a date picker using react-datepicker and a dropdown menu with times that the users can select from. These times are fetched from a firestore database. The times collection looks like this:
times collection in firestore database. And the form information collection looks like this: form-info collection in firestore database.
So when a person selects a time for a specific date, I want to remove that time from the database only for that specific date so that users can still book that same time for another date. Here is what my code looks like:
function GThirtyminsp() {
// Form values
const [date, setDate] = useState(null);
const [email, setEmail] = useState("");
const [name, setName] = useState("");
const [age, setAge] = useState("");
const [team, setTeam] = useState("");
const [number, setNumber] = useState("");
const [time, setTime] = useState(null);
// To show times on screen
const [times, setTimes] = useState([]);
const timesRef = collection(db, "30min-goalie-semiprivate-times");
const formRef = collection(db, "30min-goalie-semiprivate");
useEffect(() => {
const fetchData = async () => {
const timeData = await getDocs(timesRef);
setTimes(timeData.docs.map((doc) => ({ ...doc.data(), id: doc.id })));
};
fetchData();
}, []);
const createBooking = async () => {
await addDoc(formRef, {
name: name,
date: date,
email: email,
number: number,
team: team,
age: age,
time: time,
});
};
const handleSubmit = (e) => {
e.preventDefault();
createBooking();
setName("");
setEmail("");
setDate(null);
setNumber("");
setTeam("");
setTime(null);
setAge("");
};
return (
<div>
<h1 class="text-3xl w-full text-center pt-10 font-bold">
Book 30min Semi-Private Goalie Clinic
</h1>
<div class="flex flex-col items-center">
<form onSubmit={handleSubmit} class="flex flex-col pt-10 w-3/4">
<input
type="text"
name="name"
placeholder="Name"
value={name}
onChange={(e) => setName(e.target.value)}
class="border-2 p-3 mb-5 border-gray rounded-lg"
/>
<input
type="text"
name="email"
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
class="border-2 p-3 mb-5 border-gray rounded-lg"
/>
<input
type="text"
name="number"
placeholder="Phone Number"
value={number}
onChange={(e) => setNumber(e.target.value)}
class="border-2 p-3 mb-5 border-gray rounded-lg"
/>
<input
type="text"
name="team"
placeholder="Team Name"
value={team}
onChange={(e) => setTeam(e.target.value)}
class="border-2 p-3 mb-5 border-gray rounded-lg"
/>
<input
type="text"
name="age"
placeholder="Age"
value={age}
onChange={(e) => setAge(e.target.value)}
class="border-2 p-3 mb-5 border-gray rounded-lg"
/>
<h2 class="text-center text-xl py-5 font-bold">
Pick a Date and Time
</h2>
<div class="pb-10">
<DatePicker
className="border-2 p-3 w-full border-gray rounded-lg"
selected={date}
onChange={(date) => setDate(date)}
placeholderText="Select a Date"
/>
<div class="pt-10">
<select onChange={(e) => setTime(e.target.value)}>
{times.map((item) => {
return (
<option key={item} value={item.time}>
{item.time}
</option>
);
})}
</select>
</div>
</div>
<button
type="submit"
class="bg-accent text-white font-semibold p-3 rounded-full"
>
Submit
</button>
</form>
</div>
</div>
);
}
You can create a function that when the time is successfully booked, the time document gets deleted from the firebase firestore.
You can await the createBooking and if successful you then call the deletedoc, using the time state as the reference.
https://firebase.google.com/docs/firestore/manage-data/delete-data
Just make sure to validate that the booking was/is successful. Once you have this in-place you will want to reverse the process and add the doc if someone wants to cancel the booking.
Edit: example.
Const deleted= (time) =>{ await deleteDoc(doc(db, "30minute-inprivate etc", (time)
));
}
After giving the input of mobile number when i close the modal, then again after clicking the Form Submit button, input box shows the previously entered number. I believe model captures the previous state by itself and i want to clear it whenever we open the modal.
After entering the OTP input in Modal, if we click on the Edit mobile number and when we again enter the input in mobile number, then previously entered OTP also shows up. I want to clear it after entering the new mobile number.
I have already tried setting the state to ("") on the onclick events but it doesn't help.
I could really use some help.
Code:
export default function Form() {
// form default hooks
const {register,handleSubmit, formState: { errors, isValid },} = useForm({mode: "onChange",criteriaMode: "all",});
const {register: register2,handleSubmit: handleSubmit2,formState: { errors: errors2 },} = useForm({mode: "onChange",});
const [verifyOTPFlag, setVerifyOTPFlag] = useState(true);
//modal hooks
const [mobileNumberInput, setMobileNumberInput] = useState(true);
const [postVerificationMessage, setPostVerificationMessage] = useState();
const [otpVerificationResult, setOtpVerificationResult] = useState(false);
const [show, setShow] = useState(false);
const [otpInput, setShowOtpInput] = useState(false);
const [number, setNumber] = useState("");
const [OTP, setOTP] = useState("");
const [counter, setCounter] = useState(59);
// post office and aadhar hooks
const [districtName, setDistrictName] = React.useState("");
const [stateName, setStateName] = React.useState("");
//-------------------------modal functionalities start-------------------------
const handleClose = () => {
setShow(false);
setShowOtpInput(false);};
const handleShow = () => {
setShow(true);};
const showOtpInput = () => {
getOTP(number);
setOTP("");
setShowOtpInput(true);
setMobileNumberInput(false);
setOtpVerificationResult(false);
};
const onSubmit = (data) => {
data["district"] = districtName;
data["state"] = stateName;
setMobileNumberInput(true);
setPostVerificationMessage("");
setNumber("");
if (verifyOTPFlag) {
if (isValid) {
setShow(true);
} else {}
}
};
const onSubmit2 = () => {
verifyOTP(OTP)
.then((resp) => {
alert("OTP verification Successful");
setPostVerificationMessage(<p className="text-danger">OTP verification Successful</p>);
setVerifyOTPFlag(false);
setOtpVerificationResult(true);
setShowOtpInput(false);
})
.catch((error) => {
setPostVerificationMessage(<p className="text-danger"> OTP verification Failed. Kindly enter the correct OTP</p> )
setOtpVerificationResult(true);
});};
const onClickEditMobileNo = () => {
setShowOtpInput(!otpInput);
setOtpVerificationResult("");
setOTP("");
setMobileNumberInput(true);
};
return (
<div>
<div className="form-group">
<form onSubmit={handleSubmit(onSubmit)}>
<div className="container mt-2">
<label className="control-label">Full Name : </label>
<input
className="text-uppercase input-group input-group-lg form-control"
type="text"
name="username"
{...register("username", {
required: "Username is Required",
pattern: {
value: /^[a-zA-Z0-9\s,\'-\/:&]*$/,
message: "Entered value does not match valid name format",
},
})}
/>
<p className="errorMsg">{errors.username?.message}</p>
<label className="control-label">C/o : </label>
<input
className="text-uppercase input-group input-group-lg form-control"
type="text"
name="careof"
{...register("careof", {
required: "Name of c/o is Required",
pattern: {
value: /^[a-zA-Z0-9\s,\'-\/:&]*$/,
message: "Entered value does not match valid name format",
},
})}
/>
<p className="errorMsg">{errors.careof?.message}</p>
<label className="control-label">House No./Bldg./Apt : </label>
<input
className="text-uppercase input-group input-group-lg form-control"
type="text"
name="houseno"
{...register("houseno", {
required: "House number is Required",
})}
/>
<p className="errorMsg">{errors.houseno?.message}</p>
<div className="text-center">
<button
className="button btn-primary btn px-3 mr-1"
onClick={onSubmit}
>
Form Submit
</button>
</div>
</div>
</form>
<form onSubmit={handleSubmit2(onSubmit2)}>
{/* modal starts */}
<Modal show={show} onHide={handleClose} backdrop="static">
<Modal.Header
style={{
backgroundImage: "linear-gradient(180deg , #3f55c4 , #95a4f0",
}}
closeButton></Modal.Header>
<Collapse in={mobileNumberInput}>
<div
className="input-field-sb mt-4 ml-5"
style={{ width: "80%" }}
>
<input className="input-sb" maxLength="10" type="text" id="mobile"
// onChange={(e) => setNumber(e.target.value)}
{...register2("mobile", {
required: "Mobile number is Required",
pattern: {
value: /^[5-9]\d{9}$/,
message: "Entered value does not match valid name format",
},
onChange: (e) => setNumber(e.target.value),})}/>
<p className="errorMsg">{errors2.mobile?.message}</p>
<label className="label-sb" htmlFor="mobile">Enter Mobile Number: </label>
</div>
</Collapse>
<Modal.Body>
<Collapse in={otpInput}>
<div>
<div className="d-flex justify-content-center">
<p className="text-center"><strong>{" "} We sent you a code to verify your mobile number{" "}</strong>{" "}
<b className="text-danger">{number}</b>
<span className="mobile-text"> Enter your OTP code here</span>
</p>
</div>
<input className="input-sbj" maxLength="6" onChange={(e) => setOTP(e.target.value)}/>
</div>
</Collapse>
<Collapse in={otpVerificationResult}>
<div className="text-center">{postVerificationMessage}</div>
</Collapse>
<div className="d-flex justify-content-center col-md-12">
{otpInput ? (
<Button className="px-5 align-middle mt-4" variant="secondary" onClick={onSubmit2}>{" "} Verify</Button>) : (
<Button className="px-5 align-middle mt-4" variant="secondary"
onClick={errors2.mobile ? null : showOtpInput}>
{" "} Send OTP </Button>)}
</div>
<div className="row">
<div className={otpInput ? "col-sm-6" : "col-sm-6 d-none"}>
<a className="btn">Resend OTP in 00:{counter}</a>
</div>
<div
className={otpInput? "text-right col-sm-6": "text-right col-sm-6 d-none"}>
<a className="btn" onClick={onClickEditMobileNo}> Edit Mobile number </a>
</div>
</div>
</Modal.Body>
</Modal>
</form>
{/* modal ends */}
</div></div>);}
The easiest way would be just adding e.target.reset() in your onSubmit function.
const onSubmit = (data, e) => {
data["district"] = districtName;
data["state"] = stateName;
setMobileNumberInput(true);
setPostVerificationMessage("");
setNumber("");
e.target.reset();
if (verifyOTPFlag) {
if (isValid) {
setShow(true);
} else {}
}
};
also keep the setNumber("") like this. I think this will solve the problem.
After giving the input of mobile number when i close the modal, then again after clicking the Form Submit button, input box shows the previously entered number. I believe model captures the previous state by itself and i want to clear it whenever we open the modal.
After entering the OTP input in Modal, if we click on the Edit mobile number and when we again enter the input in mobile number, then previously entered OTP also shows up. I want to clear it after entering the new mobile number.
I have already tried setting the state to ("") on the onclick events but it doesn't help.
I could really use some help.
codesandbox
Code:
export default function Form() {
const {register,handleSubmit, formState: { errors, isValid },} = useForm({mode: "onChange",criteriaMode: "all",});
const {register: register2,handleSubmit: handleSubmit2,formState: { errors: errors2 },} = useForm({mode: "onChange",});
const [verifyOTPFlag, setVerifyOTPFlag] = useState(true);
//modal hooks
const [mobileNumberInput, setMobileNumberInput] = useState(true);
const [postVerificationMessage, setPostVerificationMessage] = useState();
const [otpVerificationResult, setOtpVerificationResult] = useState(false);
const [show, setShow] = useState(false);
const [otpInput, setShowOtpInput] = useState(false);
const [number, setNumber] = useState("");
const [OTP, setOTP] = useState("");
const [counter, setCounter] = useState(59);
// post office and aadhar hooks
const [districtName, setDistrictName] = React.useState("");
const [stateName, setStateName] = React.useState("");
//-------------------------modal functionalities start-------------------------
const handleClose = () => {
setShow(false);
setShowOtpInput(false);};
const handleShow = () => {
setShow(true);};
const showOtpInput = () => {
getOTP(number);
setOTP("");
setShowOtpInput(true);
setMobileNumberInput(false);
setOtpVerificationResult(false);
};
const onSubmit = (data) => {
data["district"] = districtName;
data["state"] = stateName;
setMobileNumberInput(true);
setPostVerificationMessage("");
setNumber("");
if (verifyOTPFlag) {
if (isValid) {
setShow(true);
} else {}
}
};
const onSubmit2 = () => {
verifyOTP(OTP)
.then((resp) => {
alert("OTP verification Successful");
setPostVerificationMessage(<p className="text-danger">OTP verification Successful</p>);
setVerifyOTPFlag(false);
setOtpVerificationResult(true);
setShowOtpInput(false);
})
.catch((error) => {
setPostVerificationMessage(<p className="text-danger"> OTP verification Failed. Kindly enter the correct OTP</p> )
setOtpVerificationResult(true);
});};
const onClickEditMobileNo = () => {
setShowOtpInput(!otpInput);
setOtpVerificationResult("");
setOTP("");
setMobileNumberInput(true);
};
return (
<div>
<div className="form-group">
<form onSubmit={handleSubmit(onSubmit)}>
<div className="container mt-2">
<label className="control-label">Full Name : </label>
<input
className="text-uppercase input-group input-group-lg form-control"
type="text"
name="username"
{...register("username", {
required: "Username is Required",
pattern: {
value: /^[a-zA-Z0-9\s,\'-\/:&]*$/,
message: "Entered value does not match valid name format",
},
})}
/>
<p className="errorMsg">{errors.username?.message}</p>
<label className="control-label">C/o : </label>
<input
className="text-uppercase input-group input-group-lg form-control"
type="text"
name="careof"
{...register("careof", {
required: "Name of c/o is Required",
pattern: {
value: /^[a-zA-Z0-9\s,\'-\/:&]*$/,
message: "Entered value does not match valid name format",
},
})}
/>
<p className="errorMsg">{errors.careof?.message}</p>
<label className="control-label">House No./Bldg./Apt : </label>
<input
className="text-uppercase input-group input-group-lg form-control"
type="text"
name="houseno"
{...register("houseno", {
required: "House number is Required",
})}
/>
<p className="errorMsg">{errors.houseno?.message}</p>
<div className="text-center">
<button
className="button btn-primary btn px-3 mr-1"
onClick={onSubmit}
>
Form Submit
</button>
</div>
</div>
</form>
<form onSubmit={handleSubmit2(onSubmit2)}>
{/* modal starts */}
<Modal show={show} onHide={handleClose} backdrop="static">
<Modal.Header
style={{
backgroundImage: "linear-gradient(180deg , #3f55c4 , #95a4f0",
}}
closeButton></Modal.Header>
<Collapse in={mobileNumberInput}>
<div
className="input-field-sb mt-4 ml-5"
style={{ width: "80%" }}
>
<input className="input-sb" maxLength="10" type="text" id="mobile"
// onChange={(e) => setNumber(e.target.value)}
{...register2("mobile", {
required: "Mobile number is Required",
pattern: {
value: /^[5-9]\d{9}$/,
message: "Entered value does not match valid name format",
},
onChange: (e) => setNumber(e.target.value),})}/>
<p className="errorMsg">{errors2.mobile?.message}</p>
<label className="label-sb" htmlFor="mobile">Enter Mobile Number: </label>
</div>
</Collapse>
<Modal.Body>
<Collapse in={otpInput}>
<div>
<div className="d-flex justify-content-center">
<p className="text-center"><strong>{" "} We sent you a code to verify your mobile number{" "}</strong>{" "}
<b className="text-danger">{number}</b>
<span className="mobile-text"> Enter your OTP code here</span>
</p>
</div>
<input className="input-sbj" maxLength="6" onChange={(e) => setOTP(e.target.value)}/>
</div>
</Collapse>
<Collapse in={otpVerificationResult}>
<div className="text-center">{postVerificationMessage}</div>
</Collapse>
<div className="d-flex justify-content-center col-md-12">
{otpInput ? (
<Button className="px-5 align-middle mt-4" variant="secondary" onClick={onSubmit2}>{" "} Verify</Button>) : (
<Button className="px-5 align-middle mt-4" variant="secondary"
onClick={errors2.mobile ? null : showOtpInput}>
{" "} Send OTP </Button>)}
</div>
<div className="row">
<div className={otpInput ? "col-sm-6" : "col-sm-6 d-none"}>
<a className="btn">Resend OTP in 00:{counter}</a>
</div>
<div
className={otpInput? "text-right col-sm-6": "text-right col-sm-6 d-none"}>
<a className="btn" onClick={onClickEditMobileNo}> Edit Mobile number </a>
</div>
</div>
</Modal.Body>
</Modal>
</form>
{/* modal ends */}
</div></div>)
;}
when applying modal, generally you can use this approach.
when you submit, clear your modal fields states so it will be like it opened for the first time when you open it again.
you can do this for when you toggle or close.
this will mean that whenever you open the modal next time it will open with clean (empty or default) data.
i have a situation where there are two buttons that i want acting as a submit.
how can i make the value of the zip code (inside formik) be combined with the value of the option (button onclick), e.g. {"option": "adult", "zip_code": "00000"}
i've found this: https://github.com/formium/formik/issues/467#issuecomment-369833667
but it's for a class component, and doesn't show how to get the button value into formik values...
import React, { useState, useEffect } from 'react';
import { Form, Formik, useField } from 'formik';
import * as Yup from 'yup';
const FORM_INPUT_BOX = "m-2 border border-gray-300 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-yellow-500 focus:border-transparent"
const FORM_INPUT_LABEL = "ml-2 text-gray-700"
const FORM_INPUT_ERROR = "break-normal relative bottom-2 left-2 text-sm text-red-500"
const FORM_DROPDOWN = "m-2 focus:ring-yellow-500 border border-gray-300 focus:border-yellow-500 h-full border-transparent bg-transparent text-gray-500 sm:text-sm rounded"
export const FORM_BUTTON = "ml-2 mr-2 py-1 border border-transparent text-medium rounded-md text-white bg-gray-600 hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500"
const CustomTextInput = ({ label, ...props }) => {
const [field, meta] =useField(props); //using the hook useField, and destructuring
return(
<> {/*so we don't return any div tags - its just a react fragment */}
<label htmlFor={props.id || props.name} className={FORM_INPUT_LABEL}> {label} </label>
<input className={FORM_INPUT_BOX}{...field}{...props} />
{meta.touched && meta.error ? (
<div className={FORM_INPUT_ERROR}>{meta.error}</div>
) : null}
</>
)
}
const ButtonMaker = (props) => {
const {mainprops,userprops,adoptprops,...optionprops} = props
return(
<>
<button className={FORM_BUTTON} id={optionprops.id} onClick={()=>{optionprops.setButtonClick(true);
optionprops.setOption(optionprops.id)}}
>{optionprops.label}</button>
</>
)
};
export default function RegistrationForm(props) {
const {mainprops,userprops,...adoptprops} = props;
const [buttonClick, setButtonClick] = useState(false);
const [option, setOption] = useState('')
const allprops = {
mainprops,
userprops,
adoptprops,
buttonClick,
setButtonClick,
setOption
};
useEffect(()=>{
if (buttonClick){
alert(option)};
},[buttonClick])
// https://regex101.com/
const zipRegExp= /^([0-9]{5})$/;
//zipRegExp: only 5 digits
const zipRegExp_plus4= /^([0-9]{5})(?:[-\s]*([0-9]{4}))?$/;
return (
<Formik
initialValues={{
zip_code : ''
}}
validationSchema={Yup.object({
zip_code: Yup.string()
.min(5,'five digits needed')
.matches(zipRegExp, 'invalid zipcode')
.required('required field'),
})}
onSubmit={ (values, { setSubmitting, resetForm }) => {
setTimeout(() => {
// alert(JSON.stringify(values, null, 2));
resetForm();
setSubmitting(false);
}, 1000)
}}
>
{props => (
<Form className='bg-white rounded px-8 py-8 mt-4 mb-4'>
<div className='flex justify-center align-center'>
<section className='m-2 w-52 flex flex-col border'>
<CustomTextInput label='Enter ZIP Code' name='zip_code' placeholder='zipcode' />
</section>
</div>
<br></br>
<div className='flex justify-center align-center'>
<ButtonMaker {...allprops} groupa='pet' groupb='adopt' id='adult' label='adult'/>
<ButtonMaker {...allprops} groupa='pet' groupb='adopt' id='puppy' label='puppy'/>
</div>
</Form>
)}
</Formik>
)
}
something else i tried:
added this to each button: formkprops={props}
and this to the button maker on click function: formkprops.submitForm()
but it doesn't work.
Try the following:
import React, { useState, useEffect } from 'react';
import { Form, Formik, useField } from 'formik';
import * as Yup from 'yup';
const FORM_INPUT_BOX = "m-2 border border-gray-300 bg-white text-gray-700 placeholder-gray-400 shadow-sm text-base focus:outline-none focus:ring-2 focus:ring-yellow-500 focus:border-transparent"
const FORM_INPUT_LABEL = "ml-2 text-gray-700"
const FORM_INPUT_ERROR = "break-normal relative bottom-2 left-2 text-sm text-red-500"
const FORM_DROPDOWN = "m-2 focus:ring-yellow-500 border border-gray-300 focus:border-yellow-500 h-full border-transparent bg-transparent text-gray-500 sm:text-sm rounded"
export const FORM_BUTTON = "ml-2 mr-2 py-1 border border-transparent text-medium rounded-md text-white bg-gray-600 hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500"
const CustomTextInput = ({ label, ...props }) => {
const [field, meta] =useField(props); //using the hook useField, and destructuring
return(
<> {/*so we don't return any div tags - its just a react fragment */}
<label htmlFor={props.id || props.name} className={FORM_INPUT_LABEL}> {label} </label>
<input className={FORM_INPUT_BOX}{...field}{...props} />
{meta.touched && meta.error ? (
<div className={FORM_INPUT_ERROR}>{meta.error}</div>
) : null}
</>
)
}
const ButtonMaker = (props) => {
const {mainprops,userprops,adoptprops,...optionprops} = props
return(
<>
<button className={FORM_BUTTON} id={optionprops.id} onClick={()=>{optionprops.setButtonClick(true);
optionprops.setOption({"option": optionprops.id, "zipcode": optionprops.zip_code})}}
>{optionprops.label}</button>
</>
)
};
export default function RegistrationForm(props) {
const {mainprops,userprops,...adoptprops} = props;
const [buttonClick, setButtonClick] = useState(false);
const [option, setOption] = useState(null)
const allprops = {
mainprops,
userprops,
adoptprops,
buttonClick,
setButtonClick,
setOption
};
useEffect(()=>{
if (buttonClick){
alert(JSON.stringify(option, null, 4))};
},[buttonClick])
// https://regex101.com/
const zipRegExp= /^([0-9]{5})$/;
//zipRegExp: only 5 digits
const zipRegExp_plus4= /^([0-9]{5})(?:[-\s]*([0-9]{4}))?$/;
return (
<Formik
initialValues={{
zip_code : ''
}}
validationSchema={Yup.object({
zip_code: Yup.string()
.min(5,'five digits needed')
.matches(zipRegExp, 'invalid zipcode')
.required('required field'),
})}
onSubmit={ (values, { setSubmitting, resetForm }) => {
setTimeout(() => {
// alert(JSON.stringify(values, null, 2));
resetForm();
setSubmitting(false);
}, 1000)
}}
>
{props => (
<Form className='bg-white rounded px-8 py-8 mt-4 mb-4'>
<div className='flex justify-center align-center'>
<section className='m-2 w-52 flex flex-col border'>
<CustomTextInput label='Enter ZIP Code' name='zip_code' placeholder='zipcode' />
</section>
</div>
<br></br>
<div className='flex justify-center align-center'>
<ButtonMaker {...allprops} groupa='pet' groupb='adopt' id='adult' label='adult' zip_code={props.values.zip_code}/>
<ButtonMaker {...allprops} groupa='pet' groupb='adopt' id='puppy' label='puppy' zip_code={props.values.zip_code}/>
</div>
</Form>
)}
</Formik>
)
}
You needed to create an option property and add a zip_code propery when the actionprops' setoption function is called. In order to display this in the alert, you needed to use the JSON.stringify function to display the option using the alert function.
**Solution for Information Requested In Comments Section by Original Poster **
You can create state management for your application or use a library for this like Redux. Inside the state management, you could have an array of objects similar to the one created above. You can then give whichever component you want access to this array. You would also need a final submit for the user to indicate when they are done, or a required amount of options the user has to choose before they can move on.
References:
StackOverflow. how to alert javascript object. https://stackoverflow.com/a/64941710/8121551. (Accessed 10 October, 2021).
I just need a fresh pair of eyes to look at my code. So the problem is, my code does work and does validate the code data input into a form. However, it only does this after pressing the submit button twice. After experimenting, I have not been able to figure out what the problem is.
It seems that it does attempt to submit to the call I'm running first (it is a post request to Airtable), and after that call processes the request, it then validates the schema.
I end up getting a 422 Processing Error if all the fields are not filled yet. If they are filled, the next page (Submit) is pushed with the Router.
So I guess what I want to do is validate the form fields before submission. Any ideas?
interface FormValues {
firstName: string,
email: string,
}
const SchedulePage: NextPage = () => {
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const postSubmit = (firstName: string, email: string) => {
setLoading(true);
airtableApi
.postAirtableSchedules(firstName, email)
.then(() => {
setLoading(false);
Router.push('/submitted');
})
.catch((err) => {
setLoading(false);
setError(err.message);
});
};
const formik = useFormik({
initialValues: {
firstName: '',
email: '',
}, validate() {
const errors: FormikErrors<FormValues> = {}
// Add the touched to avoid the validator validating all fields at once
if (formik.touched.email && !formik.values.email) {
errors.email = "Email is required";
}
if (formik.touched.firstName && !formik.values.firstName) {
errors.firstName = "First name is required";
}
return errors;
},
onSubmit: (values: any) => {
postSubmit(values.firstName, values.email);
},
});
console.log(formik.errors.email);
return (
<>
<div className="absolute w-full pt-20 bg-gray-150">
<div className="container flex items-center justify-center h-full mx-auto">
<div className="relative flex-col items-center justify-center w-full h-full md:h-auto md:w-3/4 lg:w-2/5">
<div className="flex flex-col items-center w-full h-full bg-white rounded-sm shadow-sm flex-start">
<div className="flex flex-col w-full border-t border-gray-200 bg-gray-150">
<div className="flex items-center justify-center w-full py-6 bg-black">
<img src={'https://ridebeyond.com/wp-content/uploads/2020/08/logo_beyond_white.png'} />
</div>
<div className="flex items-center justify-center w-full">
<Text
label="Please sign up for a meeting."
marginTop={6}
marginBottom={2}
/>
</div>
</div>
<div className="flex flex-col items-center justify-center w-4/5 mb-10 lg:w-2/3">
<TextInput
type={TextInputType.TEXT}
id="firstName"
name="firstName"
onChange={(event) => {
formik.handleChange(event);
}}
value={formik.values.firstName}
floatText="First Name"
marginTop={1}
error={formik.errors.firstName}
/>
<TextInput
type={TextInputType.EMAIL}
id="email"
name="email"
onChange={(event) => {
formik.handleChange(event);
}}
value={formik.values.email}
floatText="Email"
marginTop={10}
error={formik.errors.email}
/>
{error && <Text label={error} marginTop={16} />}
<Button
text="Submit"
marginTop={10}
marginBottom={16}
size={ButtonSize.LG}
handleClick={formik.handleSubmit}
isLoading={loading}
/>
</div>
</div>
</div>
</div>
</div>
</>
);
};
export default SchedulePage;
Shortened for cleanliness.
I did use Formik like this and works perfect:
For validation use Yup
<Formik
initialValues={
firstName: '',
email: ''
}
validationSchema={
Yup.object().shape({
email: Yup.string()
.email("Must be a valid email")
.max(255)
.required("Email is required"),
firstname: Yup.string()
.max(255)
.required("First name is required"),
})
}
onSubmit={(e:{firstName: string,email: string}, { resetForm }) => {
let val: any = e;
postSubmit (e.firstName,e.email);
// ur rest logic
// resetForm({
// values: {
// ...e,
// },
});
}}
>
{({ handleChange, values, initialValues, errors }) => (
// Your form jsx
)}
</Formik>