Validate form field by onChange immediately, not after additional manipulations - reactjs

I have a simple form field with formik & yup validation.
The form is submitted by changing the form field. The field is of type text, but only numbers must be entered.
In this case, if a number exceeding 10 is entered, an error should be displayed and the form should be banned.
The problem is that the field only works after the blur.
If I enter one character (onChange) - field is not valid and "Required". Only after blur or type second symbol - valid.
const schema = yup.object().shape({
name: yup
.string()
.trim()
.required('Required')
.test('amount', 'Test errror', (val) => {
console.log('S1>>>' + val);
return parseFloat(val) <= 10;
}),
});
const handleSubmit = useCallback(async (values) => {
try {
console.log('Success');
} catch (e) {
console.log('Unhandled login error :', e);
}
}, []);
<Formik
validateOnChange
initialValues={{ name: '' }}
validationSchema={schema}
onSubmit={handleSubmit}
>
{({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
}) => (
<Form className="form" onChange={handleSubmit}>
<div className="mb-4">
<Form.Group className="position-relative">
<div className="position-relative">
<Form.Control
type="text"
name="name"
className={`${touched.name ? 'is-touch ' : ''} ${
errors.name && touched.name ? ' is-invalid' : ''
} ${!errors.name && touched.name ? ' is-valid' : ''}`}
value={values.name.replace(/\D/g, '')}
onBlur={handleBlur}
onChange={handleChange}
placeholder="Name"
touched={touched.name}
/>
</div>
{errors.name && (
<Form.Control.Feedback type="invalid" className="d-block">
{errors.name}
</Form.Control.Feedback>
)}
</Form.Group>
</div>
</Form>
)}
</Formik>
So, How to validate a form field already from the first character and without blur (only onChange) and if I type (without blur) > 10 - show error?
Show error immediately, not after additional manipulations.

In the documentation, there are some props for these kind of manipulations.You can check setFieldTouched or validateField prop on this page:
https://formik.org/docs/api/formik

Related

Formik errors object is not being updated properly on input

coming into a new codebase here and it's also my first time using Formik and Yup so I will try to be as concise as possible, but bear with me.
I have some forms that were built with Formik and use a validation schema provided by Yup. I also have a useState variable to indicate whether or not an item is present in Yup's errors object that is used to prevent the user from continuing to the next form until the error is fixed. The validation works correctly initially, as when an invalid input is provided, the corresponding error is shown in the errors object. However, if I type something valid into the field and then go back and change it so that it's invalid, the errors object doesn't update to reflect that new error until the next input event, which throws off the value of the state variable checking it. A basic example:
Enter Email: testgmail.com ---> errors: {email: "Invalid email"}
Enter Email: test#gmail.com ---> errors: {}
Enter Email: test#gmail ---> errors: {}
It's not until I trigger the next input that errors populates back to {email: "Invalid email"}.
Any idea how to fix this problem? I will try to supply some cleaned up code below, but again apologies as it's a brand new codebase to me so I'm not sure how useful it will be.
const validate = Yup.object().shape({
name: Yup.string().required("This field is required"),
email: Yup.string()
.email("Invalid email format")
.required("Your email is required"),
code: Yup.string().required("This field is required"),
});
function handleInputChange(e: any, errors: FormikErrors, errorSetter: any, codeSetter: any, codeInfo: any) {
codeSetter({ ...codeInfo, [e.target.name]: e.target.value });
if (Object.keys(errors).length > 0) {
errorSetter(true);
}
else errorSetter(false)
}
<Formik
initialValues={{
name: codeInfo.name,
email: codeInfo.email,
code: codeInfo.code,
}}
onSubmit={() => {}}
validationSchema={validate}
>
{({
handleSubmit,
handleChange,
values,
errors,
touched,
handleBlur,
}) => (
<form className={styles.form} onSubmit={handleSubmit}>
<div className={styles.formTextfields}>
<div className={styles.textfields}>
<span className={styles.tag}>Email*</span>
<TextField
name="email"
value={values.email}
placeholder="test#gmail.com"
onChange={handleChange}
onBlur={handleBlur}
onInput={(e: any) => handleInputChange(e, errors)}
variant={
errors.email && touched.email ? "error" : "focus"
}
/>
{errors.email && touched.email ? (
<div className={styles.error}>{errors.email}</div>
) : null}
</div>
</form>
)}
</Formik>
Maybe there's something I am missing but I don't understand how that handleInputChange function is working... You can just try to remove that prop.
Formik is already handling field change and field blur with the handleChange and handleBlur handlers so it is already making validation checks.
Here's some working code you might use (I've removed name and code fields as they don't appear in any field on your code)
const validate = Yup.object().shape({
email: Yup.string()
.email("Invalid email format")
.required("Your email is required"),
});
const Component = () => {
return (
<Formik
initialValues={{
email: "",
}}
onSubmit={() => {}}
validationSchema={validate}
>
{({
handleSubmit,
handleChange,
values,
errors,
touched,
handleBlur,
}) => {
return (
<form onSubmit={handleSubmit}>
<div>
<span>Email*</span>
<TextField
name="email"
value={values.email}
placeholder="test#gmail.com"
onChange={handleChange}
onBlur={handleBlur}
/>
{errors.email && touched.email ? <div>{errors.email}</div> : null}
</div>
</form>
);
}}
</Formik>
);
};

Input not writing into input field.. Issue caused by React useForm Hook register validations

const { register, handleSubmit, errors, setValue } = useForm();
<div className="col pl-0 pr-3">
<FormInput
id="id"
name="name"
isAllowed={e => e.value == '' || (e.value.length <= 14 && e.floatValue >= 0)}
allowLeadingZeros={true}
decimalScale={0}
onChange={e => setName(e.target.value)}
value={Name}
ref={register({ required: { value: true, message: "Please enter name" } })}
/>
<ErrorMessage
errors={errors}
className="col-md-6"
name="name"
as="small"
/>
</div>
In above mentioned code,, here FormInput is customized from StyledInput.
After displaying invalid message, when I am trying to enter something in input field, first character is not writing in field but it is clearing invalid error message from second character writing into field. What's the problem How to solve it Can anyone help me on this ?
UPDATED
By using control input, 3rd party library can work with react-hook-form.
https://react-hook-form.com/get-started#IntegratingControlledInputs
<Controller
as={
<NumberFormat
thousandSeparator={true}
allowLeadingZeros={true}
decimalScale={0}
onValueChange={(value) => {
console.log(value);
}}
isAllowed={(e) =>
e.value === "" || (e.value.length <= 14 && e.floatValue >= 0)
}
/>
}
id="id"
name="name"
defaultValue="1234"
control={control}
rules={{
required: true,
minLength: 2
}}
/>
There is no need to use another state to control the value.
The component is register in react-hooks-form with name "name", it will create the name state and handled state change for you.
Remove the following lines:
const [name, setName] = useState(); // I think you have your own name state, remove it
value={name} // remove it
onChange={(e) => setName(e.target.value)} // remove it

onchange in a form using formik the value of the field is not updated

I'm new to react, and I'm trying to apply validations to a form.
For some reason when adding the property:
onChange={onChange}
I want to send the values to the parent component. That's why I'm using the onchange.
Nothing I write is shown in my text fields, why does this happen?
export const Son = props => {
const { onChange } = props;
return (
<Formik
initialValues={{
fullname: "",
email: ""
}}
validationSchema={Yup.object().shape({
fullname: Yup.string()
.min(2, "Your name is too short")
.required("Please enter your full name"),
email: Yup.string()
.email("The email is incorrect")
.required("Please enter your email")
})}
onSubmit={(values, { setSubmitting }) => {
const timeOut = setTimeout(() => {
console.log(values);
setSubmitting(false);
clearTimeout(timeOut);
}, 1000);
}}
>
{({
values,
errors,
touched,
handleSubmit,
isSubmitting,
validating,
valid
}) => {
return (
<Form name="contact" method="post" onSubmit={handleSubmit}>
<label htmlFor="fullname">
Fullname
<Field
type="text"
name="fullname"
autoComplete="name"
placeholder="your fullname"
onChange={onChange}
/>
</label>
{<ErrorMessage name="fullname">{msg => <p>{msg}</p>}</ErrorMessage>}
{/*errors.fullname && touched.fullname && <p>{errors.fullname}</p>*/}
<br />
<label htmlFor="email">
Email
<Field
type="email"
name="email"
autoComplete="email"
placeholder="your email"
onChange={onChange}
/>
</label>
<ErrorMessage name="email">{msg => <p>{msg}</p>}</ErrorMessage>
<br />
<button type="submit" disabled={!valid || isSubmitting}>
{isSubmitting ? `Submiting...` : `Submit`}
</button>
</Form>
);
}}
</Formik>
);
};
this is my live code:
https://stackblitz.com/edit/react-qotvwb?file=components/son_component.js
you're not using the formik handleChange at all.
I highlighted the changes that I made in https://stackblitz.com/
and you can test this working here

REACT.JS + FORMIK input field proble,

this is my first ever stack overflow question. I am trying to build a log-in page (making a full stack app with node express mongodb mongoose) and front end being REACT. I am running into an issue where the input field css does not register until I click into the input field and click out. I am using Formik to develop my form. I have two questions essentially: How can I fix this issue and how can I do an API call to my backend server which is running on localhost:3003. Here is the code:
import React from "react";
import "../App.css";
import { Formik } from "formik";
import * as EmailValidator from "email-validator";
import * as Yup from "yup";
const ValidatedLoginForm = () => (
<Formik
initialValues={{ email: "", password: "" }}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
console.log("Logging in", values);
setSubmitting(false);
}, 500);
}}
validationSchema={Yup.object().shape({
email: Yup.string()
.email()
.required("Required"),
password: Yup.string()
.required("No password provided.")
.min(8, "Password is too short - should be 8 chars minimum.")
.matches(/(?=.*[0-9])/, "Password must contain a number.")
})}
>
{props => {
const {
values,
touched,
errors,
isSubmitting,
handleChange,
handleBlur,
handleSubmit
} = props;
return (
<div className="FormCenter">
<form onSubmit={handleSubmit} className="FormFields">
<div className="FormField">
<label htmlFor="email" className="FormField__Label">
Email
</label>
<input
name="email"
type="text"
placeholder="Enter your email"
value={values.email}
onBlur={handleBlur}
onChange={handleChange}
className={
errors.email && touched.email && "error" && "FormField__Input"
}
/>
{errors.email && touched.email && (
<div className="input-feedback">{errors.email}</div>
)}
</div>
<div className="FormField">
<label htmlFor="email" className="FormField__Label">
Password
</label>
<input
name="password"
type="password"
placeholder="Enter your password"
value={values.password}
onChange={handleChange}
onBlur={handleBlur}
className={
errors.password &&
touched.password &&
"error" &&
"FormField__Input"
}
/>
{errors.password && touched.password && (
<div className="input-feedback">{errors.password}</div>
)}
</div>
<div className="FormField">
<button
type="submit"
className="FormField__Button mr-20"
onChange
>
Login
</button>
</div>
</form>
</div>
);
}}
</Formik>
);
export default ValidatedLoginForm;
This looks like a normal behaviour to me. The validation in the form will get triggered when ,
when you submit the form
when the field is touched . Becoz of this you are seeing the error message being displayed when you switch between the fields without entering the values .
You should be firing the api call from the onSubmit, were you will get to access all the form values . I would suggest you to use fetch api . https://developer.mozilla.org/en/docs/Web/API/Fetch_API
Just make your onSubmit as a asyn method and fire your api call inside it .

understanding Formik and React

This is probably not the best place to post this question but where, then?
The code below is taken from Formik's overview page and I'm very confused about the onSubmit handlers:
The form element has an onSubmit property that refers to handleSubmit which is passed on that anonymous function : <form onSubmit={handleSubmit}>. Where does that come from?
The Formik component has an onSubmit property as well:
onSubmit={(values, { setSubmitting }) => { ... }
How do these relate to each other? What is going on?
import React from 'react';
import { Formik } from 'formik';
const Basic = () => (
<div>
<h1>Anywhere in your app!</h1>
<Formik
initialValues={{ email: '', password: '' }}
validate={values => {
let errors = {};
if (!values.email) {
errors.email = 'Required';
} else if (
!/^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)
) {
errors.email = 'Invalid email address';
}
return errors;
}}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
setSubmitting(false);
}, 400);
}}
>
{({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
isSubmitting,
/* and other goodies */
}) => (
<form onSubmit={handleSubmit}>
<input
type="email"
name="email"
onChange={handleChange}
onBlur={handleBlur}
value={values.email}
/>
{errors.email && touched.email && errors.email}
<input
type="password"
name="password"
onChange={handleChange}
onBlur={handleBlur}
value={values.password}
/>
{errors.password && touched.password && errors.password}
<button type="submit" disabled={isSubmitting}>
Submit
</button>
</form>
)}
</Formik>
</div>
);
export default Basic;
The component takes onSubmit as a prop where you can execute code you want to perform when you submit your form. This prop is also given some arguments such as values (values of the form) for you to use in your onSubmit function.
The handleSubmit form is auto generated from the Formik library that automates some common form logics explained here. The handleSubmit will automatically execute onSubmit function mentioned above as part of its phases (pre-submit, validation, submission). Hope that answers your question!

Resources