I have a form within a React app that uses Formik with You for validation. The validation is working as expected apart from a user can enter an a string with one or more whitespace into the fields and this will allow the validation to pass and the form to be submitted. I cannot see an obvious way to ensure that the string entered into each field is not an empty string containing whitespace ( " " ).
Here is my code:
const formik = useFormik<yup.InferType<typeof validationSchema>>({
initialValues: {
addressLine1: portfolioState.clientAddress.addressLine1,
addressLine2: portfolioState.clientAddress.addressLine2,
postcode: portfolioState.clientAddress.postcode,
cityOrTownName: portfolioState.clientAddress.cityOrTownName,
county: portfolioState.clientAddress.county,
country: countryByLocale[onboardingState.settingsState.locale],
},
onSubmit: async () => {
console.log(Object.entries(formik.values));
const { createdDate, lastModifiedDate, postcode, ...rest } = portfolioState.clientAddress;
const addressUpdatePayload = {
...rest,
...formik.values,
addressType: AddressTypeEnum.INVOICE,
};
...
},
validationSchema,
});
<FormWrapper>
<Form onSubmit={formik.handleSubmit}>
<Form.Group style={styles.formGroupStyle}>
<Form.Label className="required">{t('auth:addressLine1.label')}</Form.Label>
<Form.Control
type="text"
maxLength={30}
name="addressLine1"
onChange={formik.handleChange}
value={formik.values.addressLine1}
isValid={formik.touched.addressLine1 && !formik.errors.addressLine1}
isInvalid={Boolean(formik.errors.addressLine1)}
/>
<span style={styles.subText}>{t('auth:addressLine1.subText')}</span>
</Form.Group>
<Form.Group style={styles.formGroupStyle}>
<Form.Label>{t('auth:addressLine2.label')}</Form.Label>
<Form.Control
type="text"
maxLength={30}
name="addressLine2"
onChange={formik.handleChange}
value={formik.values.addressLine2}
isValid={formik.touched.addressLine2 && !formik.errors.addressLine2}
isInvalid={Boolean(formik.errors.addressLine2)}
/>
<span style={styles.subText}>{t('auth:addressLine2.subText')}</span>
</Form.Group>
<Form.Group style={{ ...styles.formGroupStyle, ...styles.flexFormGroup }}>
<div style={{ marginRight: 15 }}>
<Form.Label className="required" style={{ whiteSpace: 'nowrap' }}>
{showUkInputs ? t('auth:postcode.label') : t('auth:zipCode.label')}
</Form.Label>
<Form.Control
type="text"
name="postcode"
maxLength={7}
onChange={formik.handleChange}
value={formik.values.postcode}
isValid={formik.touched.postcode && !formik.errors.postcode}
isInvalid={Boolean(formik.errors.postcode)}
/>
</div>
<div>
<Form.Label className="required">{t('auth:cityOrTownName.label')}</Form.Label>
<Form.Control
type="text"
name="cityOrTownName"
onChange={formik.handleChange}
value={formik.values.cityOrTownName}
isValid={formik.touched.cityOrTownName && !formik.errors.cityOrTownName}
isInvalid={Boolean(formik.errors.cityOrTownName)}
/>
</div>
<div style={{ marginLeft: 15 }}>
<Form.Label>{showUkInputs ? t('auth:county.label') : t('auth:state.label')}</Form.Label>
<Form.Control
type="string"
name="county"
onChange={formik.handleChange}
value={formik.values.county}
isValid={formik.touched.county && !formik.errors.county}
isInvalid={Boolean(formik.errors.county)}
/>
</div>
</Form.Group>
<Form.Group style={styles.formGroupStyle}>
<Form.Label>{t('auth:country.label')}</Form.Label>
<Form.Control
name="country"
as="select"
value={formik.values.country}
onChange={handleCountryChange()}
style={styles.countrySelect}
isValid={!formik.errors.country}
>
{countriesList.map((item: ICountrySelectValue) => (
<option
aria-selected="true"
key={item.key}
value={item.value}
selected={item.value === portfolioState.userDetails.country}
>
{item.key}
</option>
))}
</Form.Control>
</Form.Group>
<Button
id="billing-address-submit"
type="submit"
style={{
...{ backgroundColor: GlobalStyles.cultOrange, color: 'black', marginTop: 30 },
...(styles.buttonStyle as React.CSSProperties),
}}
disabled={onboardingState.uiState.allowContinue === false || formik.isSubmitting || !formik.isValid}
>
{t('common:continue')}
</Button>
</Form>
</FormWrapper>
Can anyone offer any advice?
thanks
To prevent a user from entering empty strings in the text input field, you can use
the .trim() method in the validation. Here is the link to the documentation.
[1]: https://github.com/jquense/yup#stringtrimmessage-string--function-schema
Related
i am new to react, can anyone explain to me how can i manipulate or repopulate my existing form from backend data in react.
I am trying to edit and existing item in the inventory that i wanna change values for. i am using formik with react and formik grid. for data i am using AXIOS.
What i am trying to do is to get edit a specific entry from my database which has changed values. it's like trying to update values
<Formik
validationSchema={schema}
initialValues={{
name: "",
numberOfSets: "0",
sortValue: "0",
boxType: "",
price: "",
photo: "",
}}
onSubmit={({
name,
numberOfSets,
sortValue,
boxType,
price,
photo,
}) => {
boxService.addBox(
name,
numberOfSets,
sortValue,
boxType,
price,
photo
);
alert("Box added Successfully!"); // Box or Gift it's same thing
window.location.reload(false);
}}
>
{({
values,
errors,
touched,
handleBlur,
handleSubmit,
setFieldValue,
}) => {
return (
<Form
form={form}
name="edit-gift"
onFinish={handleSubmit}
{...layout}
labelAlign="left"
>
// These are the fields i am trying to manipulate
<Form.Item name="name" label="Name">
<Input
name="name"
title="Product Name"
dataIndex="name"
key="productName"
value={values.name}
onChange={(e) => setFieldValue("name", e.target.value)}
onBlur={handleBlur}
placeholder="Please enter Box Name"
/>
{errors?.name && touched?.name && (
<Text type="danger">{errors?.name}</Text>
)}
</Form.Item>
<Form.Item name="numberOfSets" label="Number of Sets">
<Input
name="numberOfSets"
type="number"
value={values.numberOfSets}
onChange={(e) =>
setFieldValue("numberOfSets", e.target.value)
}
onBlur={handleBlur}
placeholder="Please enter Number of Sets"
/>
{errors?.numberOfSets && touched?.numberOfSets && (
<Text type="danger">{errors?.numberOfSets}</Text>
)}
</Form.Item>
<Form.Item name="sortVlaue" label="Sort Value">
<Input
name="sortVlaue"
type="number"
value={values.sortValue}
onChange={(e) => setFieldValue("sortVlaue", e.target.value)}
onBlur={handleBlur}
placeholder="Please enter soring value"
/>
{errors?.numberOfBoxes && touched?.numberOfBoxes && (
<Text type="danger">{errors?.numberOfBoxes}</Text>
)}
</Form.Item>
<Form.Item name="boxType" label="Type">
<Select
value={values.boxType}
onChange={(value) => setFieldValue("boxType", value)}
onBlur={handleBlur}
placeholder="Please enter Box Type"
>
<Select.Option value="reward">Reward</Select.Option>
<Select.Option value="doublerandom">
Double Random
</Select.Option>
</Select>
{errors?.boxType && (
<Text type="danger">{errors?.boxType}</Text>
)}
</Form.Item>
<Form.Item name="price" label="Price">
<Input
name="price"
title="Product Price"
dataIndex="price"
key="price"
value={values.price}
onChange={(e) => setFieldValue("price", e.target.value)}
onBlur={handleBlur}
placeholder="Please enter Box Price"
/>
{errors?.price && touched?.price && (
<Text type="danger">{errors?.price}</Text>
)}
</Form.Item>
<Form.Item name="photo" label="Product Picture">
<div className="dropzone-container">
{values.photo && <img src={values.photo} alt=""></img>}
{!values.photo && (
<Dropzone
onDrop={(acceptedFiles) => {
acceptedFiles.map((file) => {
console.log(file);
});
let fr = new FileReader();
fr.onload = function () {
setFieldValue("photo", fr.result);
setFieldValue("imgName", acceptedFiles[0].name);
console.log(acceptedFiles[0]);
};
fr.readAsDataURL(acceptedFiles[0]);
}}
accept={{ "image/*": [] }}
maxSize={1000000}
>
{({ getRootProps, getInputProps }) => (
<section>
<div {...getRootProps({ style })}>
<input {...getInputProps()} />
<p>
Drag 'n' drop some files here, or click to
select files
</p>
<aside>
Tips: The size ratio of the photo is: 750:216,
the maximum recommended size is 1M, and the
format is: .jpg, .jpeg, .png
</aside>
</div>
</section>
)}
</Dropzone>
)}
</div>
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
Cofirm save
</Button>
</Form.Item>
</Form>
);
}}
</Formik>
You could either:
rerender the Formik component when your data is available and pass it to the initialValues prop by doing something like
results?.data && <Formik initialValues={{...}}>...</Formik>
or set the values manually with setValues after the data is available
const {setValues, values, ...} = useFormik({...});
useEffect(() => {
setValues(results?.data); // use any fields from your data
}, [results]} // this is the data from your api
I'm using react-datetime compenent in my react-bootstrap form. Formik with Yup is used for validation.
import React from 'react';
import { Container, Form, Button, Alert, Row, Col, InputGroup } from "react-bootstrap";
import "react-datetime/css/react-datetime.css";
import { Formik} from 'formik';
import * as Icon from 'react-bootstrap-icons';
import * as yup from "yup"
import Datetime from 'react-datetime';
import moment from 'moment';
const validDOB = function( current ){
return current.isBefore(moment());
};
const schema = yup.object().shape({
userId: yup.string().required('Please enter a valid User ID'),
userName: yup.string().required('User\'s Name cannot be empty'),
userDOB: yup.string().required('User\'s Date of Birth cannot be empty'),
});
function AddWorkload(){
return (
<>
<Container>
<Row className="justify-content-md-center">
<h3 style={{textAlign: 'center'}}>Add a New Workload</h3>
<Formik
validationSchema={schema}
onSubmit={console.log}
initialValues={{
userId: '',
userName: '',
userDOB: '',
}}
>
{({
handleSubmit,
handleChange,
handleBlur,
values,
touched,
isValid,
errors,
setFieldValue,
}) => (
<Col md lg="6">
<Form noValidate onSubmit={handleSubmit}>
<Form.Group controlId="userIdInput">
<Form.Label>User ID</Form.Label>
<InputGroup>
<Form.Control
placeholder="User ID"
type="text"
name="userId"
value={values.userId}
onChange={handleChange}
isInvalid={!!errors.userId}
aria-describedby="userIdHelpBlock"
/>
<Button variant="dark"><Icon.Search /> Find User</Button>
<Form.Control.Feedback type="invalid">
{errors.userId}
</Form.Control.Feedback>
</InputGroup>
<Form.Text id="userIdHelpBlock" muted>
Please click "Find User" to fill out the details.
</Form.Text>
</Form.Group>
<Form.Group controlId="userName">
<Form.Label>User Name</Form.Label>
<Form.Control
placeholder="User Name"
type="text"
name="userName"
value={values.userName}
onChange={handleChange}
isInvalid={!!errors.userName}
/>
<Form.Control.Feedback type="invalid">
{errors.userName}
</Form.Control.Feedback>
</Form.Group>
<Form.Group controlId="userDOB">
<Form.Label>Date of Birth</Form.Label>
<Datetime
inputProps={{
placeholder: 'DOB',
id: 'userDOB',
name: 'userDOB',
}}
dateFormat="DD-MM-YYYY"
timeFormat={false}
value={values.userDOB}
isValidDate={validDOB}
onChange={(dateFromValue) => {
setFieldValue('userDOB', dateFromValue);
}
}
isInvalid={!!errors.userDOB}
/>
<Form.Control.Feedback type="invalid">
{errors.userDOB}
</Form.Control.Feedback>
</Form.Group>
<div style={{clear: 'both'}}></div>
<br></br>
<div className='text-center'>
<Button variant="dark" type="reset">Reset Form</Button>{' '}
<Button variant="success" type="submit">Save</Button>
</div>
</Form>
</Col>
)}
</Formik>
</Row>
</Container>
</>
);
}
export default AddWorkload;
Validation for userId and userName is working properly. But I can't get the validation to work for userDOB. I also tried yup.date() but it doesn't work. react-datetime uses moment.js. So, what type to use for the schema and how to get the validation working for that compenent.
Any help would be appreciated.
Thanks
I found my issue. Its because Form.Control.Feedback doesn't correspond to the component Datetime.
So, I removed the Form.Control.Feedback and replaced that with a custom div to display the error message for the Datetime component.
<Form.Group controlId="patientDOB">
<Form.Label>Date of Birth</Form.Label>
<Datetime
inputProps={{
placeholder: 'DD-MM-YYYY',
id: 'userDOB',
name: 'userDOB',
className: formik.errors.userDOB && formik.touched.userDOB ? "form-control is-invalid": "form-control"
}}
closeOnSelect={true}
dateFormat="DD-MM-YYYY"
timeFormat={false}
value={formik.values.userDOB}
isValidDate={validDOB}
onChange={(dateFromValue) => {
formik.setFieldValue('userDOB', moment(dateFromValue).format('DD-MM-YYYY'));
}
}
renderInput={(props) => {
return <input {...props} value={(formik.values.userDOB) ? props.value : ''} />
}}
/>
{formik.errors.userDOB && formik.touched.userDOB ? (
<div className="text-danger" style={{fontSize: '0.875em'}}>{ formik.errors.userDOB }</div>
) : null}
</Form.Group>
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="********"/>
So I set up datepicker within my form like so
<FieldArray
name="config"
render={(arrayHelpers) => (
<div>
{values.config.map((config, index) => (
<div key={index}>
...
<DatePicker
name={`config.${index}.date`}
type="date"
value={values.date}
className={
"form-control" +
(errors.date&& touched.date
? " is-invalid"
: "")
}
onChange={(e) =>
setFieldValue("date", e)
}
/>
The data is added to the state but as an additional field instead of updating the initial state within formik. It updates likes this.
{"domain_url":"","schema_name":"","name":"","config":[{"first":"","last":"","email":"","date":""}],"date":"2020-06-10T04:00:00.000Z"}
I would appreciate any ideas.
below is a new edit of the majority of the code.
the datepicker is not displaying the date within the form field but it is updating the state correctly, now I just need it to display correctly within the form and format the date to drop the string at the end
static propTypes = {
addTenant: PropTypes.func.isRequired,
};
onSubmit = (values) => {
values.preventDefault();
this.props.addTenant(values);
};
render() {
const {
domain_url,
schema_name,
name,
config,
} = this.state;
const TenantSchema = Yup.object().shape({
domain_url: Yup.string()
.max(255, "Must be shorter than 255 characters")
.required("Client URL header is required"),
schema_name: Yup.string()
.max(255, "Must be shorter than 255 characters")
.required("Client db name is required"),
name: Yup.string()
.max(255, "Must be shorter than 255 characters")
.required("Client name is required"),
});
return (
<div className={s.root}>
<Formik
initialValues={{
domain_url: "",
schema_name: "",
client_name: "",
config: [
{
date: "",
Tenant_description: "",
},
],
}}
// validationSchema={TenantSchema} this is commented off because it breaks
submittions
onSubmit={(values, { setSubmitting, resetForm }) => {
setSubmitting(true);
values.domain_url = values.domain_url + ".localhost";
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
resetForm();
setSubmitting(false);
}, 100);
}}
>
{({
values,
errors,
status,
touched,
handleBlur,
handleChange,
isSubmitting,
setFieldValue,
handleSubmit,
props,
}) => (
<FormGroup>
<Form onSubmit={handleSubmit}>
<legend>
<strong>Create</strong> Tenant
</legend>
<FormGroup row>
<Label for="normal-field" md={4} className="text-md-right">
Show URL
</Label>
<Col md={7}>
<InputGroup>
<Field
id="appended-input"
name="domain_url"
type="text"
value={values.domain_url}
className={
"form-control" +
(errors.domain_url && touched.domain_url
? " is-invalid"
: "")
}
/>
<ErrorMessage
name="domain_url"
component="div"
className="invalid-feedback"
/>
<InputGroupAddon addonType="append">
.localhost
</InputGroupAddon>
</InputGroup>
</Col>
</FormGroup>
<FormGroup row>
<Label for="normal-field" md={4} className="text-md-right">
Database Name
</Label>
<Col md={7}>
<Field
name="schema_name"
type="text"
className={
"form-control" +
(errors.schema_name && touched.schema_name
? " is-invalid"
: "")
}
/>
<ErrorMessage
name="schema_name"
component="div"
className="invalid-feedback"
/>
</Col>
</FormGroup>
<FormGroup row>
<Label for="normal-field" md={4} className="text-md-right">
Name
</Label>
<Col md={7}>
<Field
name="name"
type="text"
className={
"form-control" +
(errors.name && touched.name
? " is-invalid"
: "")
}
/>
<ErrorMessage
name="name"
component="div"
className="invalid-feedback"
/>
</Col>
</FormGroup>
<FieldArray
name="config"
render={(arrayHelpers) => (
<div>
{values.config.map((config, index) => (
<div key={index}>
<FormGroup row>
<Label
md={4}
className="text-md-right"
for="mask-date"
>
Tenant Description
</Label>
<Col md={7}>
<TextareaAutosize
rows={3}
name={`config.${index}.tenant_description`}
id="elastic-textarea"
type="text"
onReset={values.event_description}
placeholder="Quick description of tenant"
onChange={handleChange}
value={values.tenant_description}
onBlur={handleBlur}
className={
`form-control ${s.autogrow} transition-height` +
(errors.tenant_description &&
touched.tenant_description
? " is-invalid"
: "")
}
/>
<ErrorMessage
name="tenant_description"
component="div"
className="invalid-feedback"
/>
</Col>
</FormGroup>
<FormGroup row>
<Label
for="normal-field"
md={4}
className="text-md-right"
>
Date
</Label>
<Col md={7}>
<DatePicker
name={`config[${index}]['date']`}
selected={getIn(values, `config[${index}]
['date']`) || ''}
value={getIn(values, `config[${index}]
['date']`) || ''}
onChange={(e) =>
setFieldValue(`config[${index}]['date']`, e);
}
/>
/>
<ErrorMessage
name="date"
component="div"
className="invalid-feedback"
/>
</Col>
</FormGroup>
</div>
))}
</div>
)}
/>
<div className="form-group">
<button
type="submit"
disabled={isSubmitting}
className="btn btn-primary mr-2"
>
Save Tenant
</button>
<button type="reset" className="btn btn-secondary">
Reset
</button>
</div>
</Form>
<Col md={7}>{JSON.stringify(values)}</Col>
</FormGroup>
)}
</Formik>
</div>
);
}
}
export default connect(null, { addTenant })(TenantForm);
Change your name,value and onChange as following
import { FieldArray, getIn } from 'formik';
<DatePicker
name={`config[${index}]['date']`}
selected={getIn(values, `config[${index}]['date']`) || ''}
value={getIn(values, `config[${index}]['date']`) || ''}
onChange={(e) =>
setFieldValue(`config[${index}]['date']`, e);
}
/>
React Bootstrap Select multiple showing error in Formik as it is expecting a string but returns array
Error: Warning: The value prop supplied to must be an array if multiple is true.
Check the render method of FormControl.
I believe that the error is on FormControl.d.ts inside Formik because it only accepts a string as a type
This is the Interface that Formik exposes
export interface FormControlProps {
innerRef?: React.LegacyRef<this>;
size?: 'sm' | 'lg';
plaintext?: boolean;
readOnly?: boolean;
disabled?: boolean;
value?: string; // <-- it should also receive string[] ?
onChange?: React.FormEventHandler<this>;
type?: string;
id?: string;
isValid?: boolean;
isInvalid?: boolean;
}
This is my file from where I'm trying to get the expertise
import React from 'react';
import { Container, Row, Col, Card, Form, Button } from 'react-bootstrap';
import { connect } from 'react-redux';
import { Formik } from 'formik';
import styled from 'styled-components';
import * as Yup from 'yup';
const ExpertSignUpSchema = Yup.object().shape({
expertise: Yup.array()
.of(Yup.string())
.min(1)
.required('Required'),
});
const ExpertSignUpPage: React.FC = () => (
<Container fluid>
<Row>
<Col md={4} />
<Col>
<CardWrapper>
<Card>
<Card.Header as="h5">Expert Registration</Card.Header>
<Card.Body>
<Formik
initialValues={{
expertise: [''],
}}
validationSchema={ExpertSignUpSchema}
onSubmit={(values, { setSubmitting }) => {
console.log(values);
setSubmitting(false);
}}
render={({
values,
errors,
touched,
handleBlur,
handleChange,
handleSubmit,
isSubmitting,
}) => (
<Form noValidate onSubmit={handleSubmit}>
<Form.Control
as="select"
multiple
name="expertise"
onChange={handleChange}
onBlur={handleBlur}
value={values.expertise} // <--- it should allow an array of strings, currently the code won't compile or won't update the form value as it has multiple in the form control
isValid={touched.expertise && !errors.expertise}
isInvalid={!!errors.expertise}
>
<option value="YOGA">Yoga</option>
<option value="PERSONAL_TRAINER">Personal Trainer</option>
<option value="LIFE_COACH">Life Coach</option>
<option value="NUTRITIONIST">Nutritionist</option>
</Form.Control>
</Form.Group>
<Button
variant="outline-primary"
type="submit"
block={true}
disabled={isSubmitting}
>
Register
</Button>
</Form>
)}
/>
</Card.Body>
</Card>
</CardWrapper>
</Col>
<Col md={4} />
</Row>
</Container>
);
export default connect(
null,
null,
)(ExpertSignUpPage);
const CardWrapper = styled.div`
margin-top: 5rem;
`;
For some reason I'm unable to even get the values in the array when I update the the definition file to string | string[].
It took two days to make it error-free... and I had hoped this would be work at your end..
import React from 'react';
import { Container, Row, Col, Image, Form, Button } from 'react-bootstrap';
import style from '../styles/Contact.module.css';
import { Formik, Field} from 'formik';
import * as Yup from 'yup';
const dropdown=[
{
key:"Select an option",
value:""
},
{
key:"Option 1",
value:"option1"
},
{
key:"Option 2",
value:"option2"
},
{
key:"Option 3",
value:"option3"
}
]
// RegEx for phone number validation
const phoneRegExp = /^(\+?\d{0,4})?\s?-?\s?(\(?\d{3}\)?)\s?-?\s?(\(?\d{3}\)?)\s?-?\s?(\(?\d{4}\)?)?$/
// Schema for yup
const validationSchema = Yup.object().shape({
name: Yup.string()
.min(2, "*Names must have at least 2 characters")
.max(30, "*Names can't be longer than 30 characters")
.required("*Name is required"),
email: Yup.string()
.email("*Must be a valid email address")
.max(100, "*Email must be less than 100 characters")
.required("*Email is required"),
phone: Yup.string()
.min(10, "*Names can't be longer than 10 numbers")
.matches(phoneRegExp, "*Phone number is not valid")
.required("*Phone number required"),
msg: Yup.string()
.min(2, "*Messages must have at least 2 characters")
.max(250, "*Messages can't be longer than 250 characters")
.required("*Messages is required"),
selectionOption: Yup.string()
// .of(Yup.string())
// .min(1)
.required('Required'),
});
const Signup = () => {
return (
<>
<Formik
initialValues={{ name: "", email: "", phone: "", msg: "",selectionOption:"" }}
validationSchema={validationSchema}
onSubmit={(values, { setSubmitting, resetForm }) => {
// When button submits form and form is in the process of submitting, submit button is disabled
console.log(values)
setSubmitting(true);
// Simulate submitting to database, shows us values submitted, resets form
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
resetForm();
setSubmitting(false);
}, 500);
}}
>
{({ values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
isSubmitting }) => (
<Form className="form" onSubmit={handleSubmit} autoComplete="off" name="contact" method="POST" >
<Row className="mb-5">
<Col lg={6} md={6} sm={12}>
<Form.Group controlId="formName">
<Form.Label className="form_label" >FullName</Form.Label>
<Form.Control
type="text"
name="name"
placeholder="Full Name"
onChange={handleChange}
onBlur={handleBlur}
value={values.name}
className={touched.name && errors.name ? "has-error" : null}
/>
{touched.name && errors.name ? (
<div className="error-message">{errors.name}</div>
) : null}
</Form.Group>
</Col>
<Col lg={6} md={6} sm={12}>
<Form.Group>
<Form.Label className="form_label" >Number</Form.Label>
<Form.Control
type="text"
name="phone"
placeholder="Phone"
onChange={handleChange}
onBlur={handleBlur}
value={values.phone}
className={touched.phone && errors.phone ? "has-error" : null}
/>
{touched.phone && errors.phone ? (
<div className="error-message">{errors.phone}</div>
) : null}
</Form.Group>
</Col>
</Row>
<Row className="mb-5">
<Col lg={6} md={6} sm={12}>
<Form.Group>
<Form.Label className="form_label" >Email</Form.Label>
<Form.Control
type="text"
name="email"
placeholder="Email"
onChange={handleChange}
onBlur={handleBlur}
value={values.email}
className={touched.email && errors.email ? "has-error" : null}
/>
{touched.email && errors.email ? (
<div className="error-message">{errors.email}</div>
) : null}
</Form.Group>
</Col>
<Col lg={6} md={6} sm={12}>
{/* <Form.Select aria-label="Default select example">
<option>Open this select menu</option>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</Form.Select> */}
<Form.Group controlId="exampleForm.ControlSelect1">
<Form.Label>Example select</Form.Label>
<Form.Control as="select" name ="selectionOption" onChange={handleChange}
onBlur={handleBlur} value={values.selectionOption}
className={touched.selectionOption && errors.selectionOption ? "has-error" : null}
>
{
dropdown.map(drop=>{return(
<option key={drop.value} value={drop.value}>
{drop.key}
</option>
)
}
)
}
</Form.Control>
{/* <ErrorMessage name="selectionOption"></ErrorMessage> */}
{touched.selectionOption && errors.selectionOption ? (
<div className="error-message">{errors.selectionOption}</div>
) : null}
{/* <Form.Label>Example select</Form.Label>
<Field as="select" name ="selectionOption" onChange={handleChange}
onBlur={handleBlur} value={values.selectionOption}
style={{ display: "block" }}
// isValid={touched.selectionOption && !errors.selectionOption}
// isInvalid={!errors.selectionOption}
className={touched.selectionOption && errors.selectionOption ? "has-error" : null}
>
<option className='text-muted'>---</option>
<option value="ortho">ortho</option>
<option value="pedri">pedri</option>
<option value="crown">crown</option>
</Field>
{touched.selectionOption && errors.selectionOption ? (
<div className="error-message">{errors.selectionOption}</div>
) : null} */}
</Form.Group>
</Col>
</Row>
<Row className="mb-5">
<Col lg={12} md={12} sm={12}>
<Form.Group controlId="formmsg">
<Form.Label>Messages :</Form.Label>
<Form.Control
type="text"
name="msg"
as="textarea" rows={4}
placeholder="Query / Feedback"
onChange={handleChange}
onBlur={handleBlur}
value={values.msg}
className={touched.msg && errors.msg ? "has-error" : null}
/>
{touched.msg && errors.msg ? (
<div className="error-message">{errors.msg}</div>
) : null}
</Form.Group>
</Col>
</Row>
<Button type="submit" className={style.customizeBtn} name="contact" id="contact" disabled={isSubmitting}>
<Image src="img/send.png" className={style.imgBtn} />
<span className={style.titleBtn}>Submit</span>
</Button>
</Form>
)}
</Formik>
</>
)
}
export default Signup;