I'm utilising Formik and React-Bootstrap to construct a user registration form. For now, I'm just console.logging the values captured from the form but for some reason my form does not capture the values from <Form.Check> element.
I would really appreciate any help as I've been struggling for a few hours!
const Register = () => {
const formik = useFormik({
initialValues: {
firstname: '',
surname: '',
email: '',
password: '',
role: 'user',
secondaryinterest: [''],
},
validationSchema: Yup.object({
firstname: Yup.string()
.min(2, 'Your name is too short')
.max(100, 'Your name is too long')
.required('We require your name'),
surname: Yup.string()
.min(2, 'Your name is too short')
.max(100, 'Your name is too long')
.required('We require your name'),
email:Yup.string()
.required('Sorry the email is required')
.email('This is not a valid email'),
password:Yup.string()
.required('Sorry the password is required'),
secondaryinterest: Yup.array()
.min(1, "You need to select at least one"),
}),
onSubmit:(values) => {
console.log(values)
}
})
return(
<Form onSubmit={formik.handleSubmit}>
<Form.Group>
<Form.Label>Select the five most relevant for you</Form.Label>
{['Football', 'Golf', 'Rugby', 'Tennis'].map((secondaryinterest) => (
<div key={`${secondaryinterest}`} className="mb-3">
<Form.Check
type='checkbox'
name='secondaryinterest'
placeholder="secondaryinterest"
id={`${secondaryinterest}`}
label={`${secondaryinterest}`}
onChange={formik.handleChange}
{...formik.getFieldProps('secondaryinterest')}
/>
</div>
))}
</Form.Group>
<Row className="mb-3">
<Form.Group as={Col} controlId="formGridFirstname">
<Form.Label>First Name</Form.Label>
<Form.Control
type="text"
name="firstname"
variant="outlined"
{...formik.getFieldProps('firstname')}
/>
{formik.touched.firstname && formik.errors.firstname ? (
<div>{formik.errors.firstname}</div>
) : null}
</Form.Group>
<Form.Group as={Col} controlId="formGridSurname">
<Form.Label>Last Name</Form.Label>
<Form.Control
type="text"
name="surname"
variant="outlined"
{...formik.getFieldProps('surname')}
/>
{formik.touched.surname && formik.errors.surname ? (
<div>{formik.errors.surname}</div>
) : null}
</Form.Group>
</Row>
<Row className="mb-3">
<Form.Group as={Col} controlId="formGridEmail">
<Form.Label>E-mail</Form.Label>
<Form.Control
type="email"
name="email"
variant="outlined"
{...formik.getFieldProps('email')}
/>
{formik.touched.email && formik.errors.email ? (
<div>{formik.errors.email}</div>
) : null}
</Form.Group>
<Form.Group as={Col} controlId="formGridPassword">
<Form.Label>Enter your password</Form.Label>
<Form.Control
type="password"
name="password"
variant="outlined"
{...formik.getFieldProps('password')}
/>
{formik.touched.password && formik.errors.password ? (
<div>{formik.errors.password}</div>
) : null}
</Form.Group>
</Row>
<Button variant="primary" type="submit">
Register
</Button>
</Form>
}
Console log output is:
{firstname: "Dave", surname: "Kula", email: "davekula#gmail.com", password: "ddhshja", role: "user", secondary interest: [],...}
This part actually doesn't do anything. What you want to do actually, when you set the checkmark, it should add it to the array of secondaryinterest. However you didn't give instructions and Formik cannot just guess it.
{['Football', 'Golf', 'Rugby', 'Tennis'].map((secondaryinterest) => (
<div key={`${secondaryinterest}`} className="mb-3">
<Form.Check
type='checkbox'
name='secondaryinterest'
placeholder="secondaryinterest"
id={`${secondaryinterest}`}
label={`${secondaryinterest}`}
onChange={formik.handleChange}
{...formik.getFieldProps('secondaryinterest')}
/>
</div>
))}
Easier change for you, I suggest, create new initial values for each checkbox. Make them separate.
I was able to fix it and thought to post the answer in case it helps someone else a a later stage
{['Football', 'Golf', 'Rugby', 'Tennis'].map((secondaryinterest) => (
<div key={`${secondaryinterest}`} className="mb-3">
<Form.Check
type='checkbox'
name='secondaryinterest'
value={`${secondaryinterest}`}
label={`${secondaryinterest}`}
onChange={formik.handleChange}
/>
</div>
))}
I stipulated the name and value fields. Also the {...formik.getFieldProps('secondaryinterest')} was redundant.
Related
I have a form using formik, comprising a date field and a text field.
when I add a date in the form the text field is automatically put in error.
I think it comes from the initavalues
initialValues={{
comment: '',
endDate: '',
}}
it checks the value of the comment field which is empty and declares it in error.
if I remove comment from initialvalues I end up with an error :
Property 'comment' does not exist on type '{ endDate: string; }'.
How to make so that the field comment is not in error when I empty it or I validate the form?
const FormTest = (props: {
mvts: Movement[];
tiersRef: string;
masterRef: string;
submitCallback: any;
}) => {
const schema = yup.object().shape({
comment: yup.string().required(),
endDate: yup.string().required(),
});
return (
<>
<Formik
initialValues={{
comment: '',
endDate: '',
}}
onSubmit={(values) => {}}
validationSchema={schema}
>
{(formikProps) => (
<form
onSubmit={formikProps.handleSubmit}
aria-label="form-add-promise"
>
<section>
<p>
<I18nWrapper
translateKey={'event.form-create-promise.explanations'}
/>
</p>
</section>
<section>
<Row>
<Form.Group controlId="datePromise" as={Row}>
<Form.Label column lg={6}>
<I18nWrapper
translateKey={'event.form-create-promise.date-promise'}
/>
</Form.Label>
<Col lg={6}>
<Form.Control
value={formikProps.values.comment}
type="date"
name="endDate"
aria-label="from date"
role="date"
onChange={formikProps.handleChange}
isInvalid={!!formikProps.errors.endDate}
/>
<Form.Control.Feedback
type="invalid"
role="alert"
aria-label="no date promise"
>
<FontAwesomeIcon
icon={faTimes}
className="me-2"
size="lg"
/>
<I18nWrapper
translateKey={'event.form-create-promise.error.date'}
/>
</Form.Control.Feedback>
</Col>
</Form.Group>
</Row>
</section>
<section>
<Form.Group controlId="eventComment">
<Form.Label>
<I18nWrapper
translateKey={'event.form-create-promise.error.comment'}
/>
</Form.Label>
<Form.Control
value={formikProps.values.comment}
onChange={formikProps.handleChange}
as="textarea"
aria-label="from textarea"
rows={3}
name="comment"
role="textbox"
isInvalid={!!formikProps.errors.comment}
/>
<Form.Control.Feedback
type="invalid"
role="alert"
aria-label="no comment"
>
<FontAwesomeIcon icon={faTimes} className="me-2" size="lg" />
<I18nWrapper
translateKey={'reminder.modal.phone-reminder.error'}
/>
</Form.Control.Feedback>
</Form.Group>
</section>
<div className="text-center">
<GenericButton
label={'event.form-create-promise.btn-creation'}
type="submit"
disabled={!formikProps.isValid}
/>
</div>
</form>
)}
</Formik>
</>
);
};
export default FormTest;
I am trying to validate the password and confirm password field validation. I tried using Redux Form but getting errors.
Is there any passwordsMatch default function, just like checking valid emails?
Is there anyone who knows how to do it?
Following is the code that I have done.
import React, {Component} from 'react'
import { Container, Row, Col, Card, Button } from 'react-bootstrap';
import {Control, LocalForm, Errors} from 'react-redux-form';
const required = (val) => val && val.length;
const maxLength = (len) => (val) => !(val) || (val.length <= len);
const minLength = (len) => (val) => (val) && (val.length >= len);
// for numbers
//const isNumber = (val) => !isNaN(Number(val));
const validEmail = (val) => /^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(val);
<LocalForm onSubmit={(values) => this.handlerSubmit(values)}>
<Row className="form-group">
<Col>
<Control.text model=".name"
name="name"
className="form-control"
placeholder="Enter your Name"
validators={{
required, minLength: minLength(3), maxLength: maxLength(15)
}}
/>
<Errors
className="text-danger"
model=".name"
show="touched"
messages={{
required: 'Required',
minLength: 'Must be greater than 2 characters',
maxLength: 'Must be 15 characters or less'
}}
/>
</Col>
</Row><br></br>
<Row className="form-group">
<Col>
<Control.text model=".email"
name="email"
className="form-control"
placeholder="Enter a valid email address"
validators={{
required, validEmail
}}
/>
<Errors
className="text-danger"
model=".email"
show="touched"
messages={{
required: 'Required',
validEmail: 'Invalid Email Address'
}}
/>
</Col>
</Row><br></br>
<Row className="form-group">
<Col>
<Control type="password" model=".password"
name="password"
className="form-control"
placeholder="Enter your password"
validators={{
required,
passwordsMatch: (value) => vals.password === vals.conPassword,
}}
/>
<Errors
className="text-danger"
model=".password"
show="touched"
messages={{
required: 'Required',
passwordsMatch: 'Password doesnot match'
}}
/>
</Col>
</Row><br></br>
<Row className="form-group">
<Col>
<Control type="password" model=".conpassword"
name="conpassword"
className="form-control"
placeholder="Please confirm your password"
validators={{
required
}}
/>
<Errors
className="text-danger"
model=".conpassword"
show="touched"
messages={{
required: 'Required',
passwordsMatch: 'Password doesnot match'
}}
/>
</Col>
</Row><br></br>
<Row className="form-group">
<Col>
<Checkbox name="agree" value={this.state.agree} onChange={this.handleAgree}
> <strong>I accepts the terms and condition.</strong></Checkbox>
</Col>
</Row>
<Alert variant="info" >Note: Please agree our terms and condition to proceed forward.<br></br>
Thank you!</Alert>
<br></br>
<Button type="submit" className="rounded-pill bg-secondary" disabled={!(this.state.agree)}>Submit</Button>
</LocalForm>
I've created custom function from my form using this method
const matchInput = (input, allInputs) => {
return input === allInputs.password ? undefined : 'Passwords do not match';
}
<Field
name="password"
component={InputElement}
label={'Password'}
type={'password'}
required={true}
placeholder="********"/>
<Field
name="cpassword"
component={InputElement}
validate={[matchInput]}
type="password"
label={'Confirm Password'}
required={true}
placeholder="********"/>
I am starting in React and now I have the challenge of form validation and for this, looking for ways to work with the validations I found the Formik and Yup libraries
But it turns out that there is no example of how to validate an "input type = 'date'", I only see examples where they use "DatePicker", to which I ask if there is any way to be able to solve this using "input type = 'date'
Then I will show you how I am trying to validate this date.
const validationSchema = Yup.object().shape({
name: Yup.string()
.min(2,"El nombre debe contener mas de 2 caracteres")
.max(60,"El nombre no debe exceder de los 60 caracteres")
.required("*El nombre es requerido"),
inicio: Yup.date()
.min(Yup.ref('originalEndDate'),
({ min }) => `Date needs to be before ${formatDate(min)}!!`,)
});
function formatDate(date) {
return new Date(date).toLocaleDateString()
}
<Formik initialValues={{ name:"",inicio:""}} validationSchema={validationSchema}>
{( {values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
isSubmitting }) => (
<Form.Group>
<Form.Row>
<Form.Label column="sm" lg={1}>
Creada Por:
</Form.Label>
</Form.Row>
<Form.Row className="col-form-label">
<Form.Label column="sm" lg={1}>
Nombre:
</Form.Label>
<Col>
<div class="col-10">
<Form.Control type="text" defaultValue={values.name} name="name" placeholder="Nombre de campaña"
onChange={handleChange}
onBlur={handleBlur}
className={touched.name && errors.name ? "error":null}/>
{/* Applies the proper error message from validateSchema when the user has clicked the element and there is an error, also applies the .error-message CSS class for styling */}
{touched.name && errors.name ? (
<div className="error-message">{errors.name}</div>
): null
}
</div>
</Col>
</Form.Row>
<Form.Row>
<Form.Label column="sm" lg={1}>
Inicio:
</Form.Label>
<Col>
<div className="col-10">
<Form.Control type="date" placeholder="" defaultValue={values.inicio}
onChange={handleChange}
onBlur={handleBlur}
className={touched.inicio && errors.inicio ? "error":null}
/>
</div>
</Col>
<Form.Label column="sm" lg={1}>
Fin:
</Form.Label>
<Col>
<div className="col-10">
<Form.Control type="date" placeholder="2011-08-19"
/>
</div>
</Col>
</Form.Row>
<h5>Indique el objetivo a cumplir para esta campaña</h5>
<Container>
<Form.Check required label="Incrementar volumen de ventas"/>
<Form.Check required label="Incrementar repetición de venta"/>
<Form.Check required label="Mejorar lealtad"/>
<Form.Check required label="Crear awearness"/>
<Form.Check required label="Acción correctiva"/>
</Container>
<Container>
<Button as="input" type="button" value="regresar" />{' '}
<Button as="input" variant="primary" type="submit" value="Crear campaña"/>
</Container>
</Form.Group>
)}
</Formik>
I am looking for a solution for this if it exists
Using transforms:
import { date, object } from "yup";
const today = new Date();
const schema = object({
birthday: date().transform(parseDateString).max(today),
});
const isValid = schema.validateSync({
birthday: "2020-02-02",
});
Ref: https://codedaily.io/tutorials/175/Yup-Date-Validation-with-Custom-Transform
Yup: https://github.com/jquense/yup#mixedtransformcurrentvalue-any-originalvalue-any--any-schema
I'm new to React and I have done a multistep form for signing up using React bootstrap, Formik, and validation with Yup. I want to add functionality that will allow me to format (or mask) user inputs in a couple of fields.
While user typing, I want to format the phone input to this format: 111-111-1111. The postal code to format: N0G 1A3. How I can do this? Any suggestions? Do I need to add any libraries? What should I do?
Here is the code I did:
export const step1Scehma = Yup.object({
firstName: Yup.string()
.required("This field is required"),
lastName: Yup.string()
.required("This field is required"),
email: Yup.string()
.email()
.required("Email is required"),
password: Yup.string()
.required("This field is required")
.matches(
"^(?=.*[A-Za-z])(?=.*d)(?=.*[#$!%*#?&])[A-Za-zd#$!%*#?&]{8,}$",
"Must Contain at least 8 Characters: One Uppercase, One Lowercase, One Number and one
special case Character"
),
phone: Yup.string()
.required("This field is required")
});
export const Step1 = ({ formik }) => {
const { handleChange, values, errors, touched } = formik;
return (
<React.Fragment>
<Container>
<Card.Title className="text-center">New User</Card.Title>
<Card.Body>
<Form.Group as={Col}>
<Form.Label>First Name</Form.Label>
<Form.Control
type="text"
name="firstName"
onChange={handleChange}
value={values.firstName}
isValid={touched.firstName && !errors.firstName}
isInvalid={!!errors.firstName}
className={touched.firstName && errors.firstName ? "error" : null}
/>
{touched.firstName && errors.firstName ? (<div className="error-message">{errors.firstName}</div>): null}
</Form.Group>
<Form.Group as={Col}>
<Form.Label>Last Name</Form.Label>
<Form.Control
type="text"
name="lastName"
onChange={handleChange}
value={values.lastName}
isValid={touched.lastName && !errors.lastName}
isInvalid={!!errors.lastName}
className={touched.lastName && errors.lastName ? "error" : null}
/>
{touched.lastName && errors.lastName ? (<div className="error-message">{errors.lastName}</div>): null}
</Form.Group>
<Form.Group as={Col} >
<Form.Label>Email</Form.Label>
<Form.Control
type="text"
name="email"
onChange={handleChange}
value={values.email}
isValid={touched.email && !errors.email}
isInvalid={!!errors.email}
className={touched.email && errors.email ? "error" : null}
/>
{touched.email && errors.email ? (<div className="error-message">{errors.email}</div>): null}
</Form.Group>
<Form.Group as={Col} >
<Form.Label>Password</Form.Label>
<Form.Control
type="password"
name="password"
onChange={handleChange}
value={values.password}
isValid={touched.password && !errors.password}
isInvalid={!!errors.password}
className={touched.password && errors.password ? "error" : null}
/>
{touched.password && errors.password ? (<div className="error-message">{errors.password}</div>): null}
</Form.Group>
<Form.Group as={Col} >
<Form.Label>Phone Number</Form.Label>
<Form.Control
type="tel"
name="phone"
onChange={handleChange}
value={values.phone}
isValid={touched.phone && !errors.phone}
isInvalid={!!errors.phone}
className={touched.phone && errors.phone ? "error" : null}
/>
{touched.phone && errors.phone ? (<div className="error-message">{errors.phone}</div>): null}
</Form.Group>
</Card.Body>
</Container>
</React.Fragment>
);
};
You can use https://github.com/sanniassin/react-input-mask
https://www.npmjs.com/package/react-input-mask
The examples are very detailed. I used this with Yup and Material UI.
<InputMask mask="999-999-9999" onChange={ handleChange } onBlur={ handleBlur } value={values.billing_phone} error={errors.billing_phone && touched.billing_phone} helperText={(errors.billing_phone && touched.billing_phone) && errors.billing_phone}>
{(inputProps) => <TextField {...inputProps} className={classes.MuiInputBase} id="billing_phone" variant="outlined" name="billing_phone" placeholder={addressObj.phone} />}
</InputMask>
If you're not using a plain <input /> you'll have to wrap your element like I did. You can find the discussion about this on the NPM page.
I'm making a form with React, Formik, react-bootstrap, and yup for validation. I am trying to display validation errors, but the touched property is not being populated with the fields.
const schema = yup.object({
name: yup.string().required(),
email: yup
.string()
.email()
.required(),
});
const ChildForm = props => {
const { child: { name = '', email = '' } = {} } = props;
const submitHandler = ({name, email}) => console.log(name, email);
return (
<Formik
validationSchema={schema}
onSubmit={submitHandler}
initialValues={{ name, email }}
render={({ handleSubmit, handleChange, values, touched, errors }) =>
{
console.log('touched: ', touched);
return (
<Form noValidate className="mt-4" onSubmit={handleSubmit}>
<Form.Row>
<Form.Group as={Col} controlId="name">
<Form.Label>Full Name</Form.Label>
<Form.Control
name="name"
required
value={values.name}
onChange={handleChange}
isValid={touched.name && !errors.name}
isInvalid={touched.name && errors.name}
type="text"
placeholder="Your child's name"
/>
<Form.Control.Feedback>Looks good!</Form.Control.Feedback>
<Form.Control.Feedback type="invalid">
{errors.name || 'Please enter your child\'s name'}
</Form.Control.Feedback>
</Form.Group>
</Form.Row>
<Form.Row>
<Form.Group as={Col} controlId="email">
<Form.Label>Email Address</Form.Label>
<Form.Control
name="email"
required
value={values.email}
onChange={handleChange}
isValid={touched.email && !errors.email}
isInvalid={touched.email && errors.email}
type="text"
placeholder="Your child's email address"
/>
<Form.Control.Feedback>
No spam, we promise!
</Form.Control.Feedback>
<Form.Control.Feedback type="invalid">
{errors.email || 'Please enter a valid email address'}
</Form.Control.Feedback>
</Form.Group>
</Form.Row>
<Form.Row className="float-right">
<Button variant="success" onClick={handleSubmit}>
<Icon icon={faSave} />
Submit
</Button>
</Form.Row>
</Form>
);
}}
/>
);
}
What am I doing wrong here? The console.log(touched) always shows an empty object.
#djheru Your solution is correct because Formik sets touched flags on blur event instead of on change. Here is Formik author comment about this:
You have to call Formiks handleBlur to notify Formik that blur event has been triggered - so yes, these handlers are needed.
I got it working by accessing the handleBlur function that's passed in the render function argument, and adding that as an onBlur handler for each of the form elements. Not sure if that's needed because I'm using react-bootstrap form components, but the react-bootstrap docs have a Formik example, but the touched object was not getting updated.
(
<Formik
validationSchema={schema}
onSubmit={submitForm}
initialValues={{ name, email }}
render={({
handleSubmit,
handleChange,
handleBlur, // handler for onBlur event of form elements
values,
touched,
errors,
}) => {
return (
<Form noValidate className="mt-4" onSubmit={handleSubmit}>
<Form.Row>
<Form.Group as={Col} controlId="nameControl">
<Form.Label>Full Name</Form.Label>
<Form.Control
name="name"
required
value={values.name}
onChange={handleChange}
onBlur={handleBlur} // This apparently updates `touched`?
isValid={touched.name && !errors.name}
isInvalid={touched.name && errors.name}
type="text"
placeholder="Your child's name"
/>
<Form.Control.Feedback>Looks good!</Form.Control.Feedback>
<Form.Control.Feedback type="invalid">
{errors.name || 'Please enter your child\'s name'}
</Form.Control.Feedback>
</Form.Group>
</Form.Row>