how to add dynamic validation in form using reactjs - javascript

I am using ant design in my demo application. I want to add dynamic validation of mobile number in my application.
In my form there two field
select field
input field
I want to add validation in the input field when select field in mobile(mobile number should be 10 digits).in other words I want to add validation of mobile number on input field only when user select mobile from select box
https://ant.design/components/form/
here is my code
https://codesandbox.io/s/holy-voice-o4wbj
<Form.Item>
{getFieldDecorator("value", {
rules: [
{ required: true, message: "Please input search value!" },
{ pattern: /[2-9]{2}\d{8}/, message: "Please input !" }
]
})(
<Input
style={{ width: 180 }}
// prefix={<Icon type="user" style={{color: 'rgba(0,0,0,.25)'}}/>}
placeholder="searchValue"
/>
)}
</Form.Item>
can we add this validation ?

You need to set rules as per some conditions like so:
const rules = mobileValidation
? [
{ required: true, message: "Please input a number!" },
{ pattern: /^[2-9]{2}\d{8}$/, message: "Please input 10 digit number!" }
]
: null;
Since you need only 10 digit number, you need to add ^ at the start and $ at the end of the regex pattern i.e. /^[2-9]{2}\d{8}$/
jsx
import React, { useState } from "react";
import { Form, Icon, Input, Button, Select } from "antd";
const { Option } = Select;
const SearchForm = props => {
const [mobileValidation, setMobileValidation] = useState(false);
const [isOptionSelected, setIsOptionSelected] = useState(false);
const { getFieldDecorator, getFieldsError } = props.form;
const handleSubmit = e => {
e.preventDefault();
mobileValidation && props.form.validateFields({ force: true });
};
const handleChange = value => {
setIsOptionSelected(true);
setMobileValidation(value === "mobile no");
};
const rules = mobileValidation
? [
{ required: true, message: "Please input a number!" },
{ pattern: /^[2-9]{2}\d{8}$/, message: "Please input 10 digit number!" }
// { pattern: /^\d{10}$/, message: "Please input 10 digit number!" }
]
: null;
return (
<div style={{ height: 80, display: "flex", justifyContent: "flex-end" }}>
<Form layout="inline" onSubmit={handleSubmit}>
<Form.Item>
{getFieldDecorator("searchBy", {
// initialValue: this.props.transactionEditableMode ? this.props.transactionEditableModeData.from : '',
rules: [{ required: true, message: "Please select your From!" }]
})(
<Select
style={{ width: 180 }}
placeholder="Select a option"
onChange={handleChange}
>
{[
{ text: "Caf Nos", value: "cafs" },
{ text: "mobile no", value: "mobile no" }
].map(i => {
return (
<Option key={i} value={i.value}>
{i.text}
</Option>
);
})}
</Select>
)}
</Form.Item>
<Form.Item>
{getFieldDecorator("value", {
rules
})(
<Input
style={{ width: 180 }}
// prefix={<Icon type="user" style={{color: 'rgba(0,0,0,.25)'}}/>}
placeholder="search a number"
name="input"
/>
)}
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
Search
</Button>
{!isOptionSelected && <h3>Select an option</h3>}
</Form.Item>
</Form>
</div>
);
};
const WrappedSearchForm = Form.create({ name: "search_form" })(SearchForm);
export default WrappedSearchForm;
Is that what you were looking for? let me know
Side note: Read about validateFields()

that worked
<Form.Item>
{getFieldDecorator("value", {
rules : mobileValidation ? [
{ required: true, message: "Please input a number!" },
{ pattern: /^[2-9]{2}\d{8}$/, message: "Please input 10 digit number!" }] : []
})(
<Input
style={{ width: 180 }}
// prefix={<Icon type="user" style={{color: 'rgba(0,0,0,.25)'}}/>}
placeholder="search a number"
name="input"
/>
)}

Related

react onchange event overrides text field value

I wanna asign the email value to the text field but it does not work but When i tried to put it on a text the value is there like for example on a span , the value of emailAddress should be the value of the textfield , any idea why does this not work guys ?
Thanks.
<span style={{paddingTop:5}}>
Full Name: {email.firstName} {email.lastName} {email.emailAddress}
</span>
#html
<TextField
type="text"
style={{ width: "95%" }}
onChange={($event) => emailOnChange($event, prop.id, mIndex)}
label="Email Address"
variant="filled"
name={email.emailAddress}
value={email.emailAddress}
defaultValue={email.emailAddress}
// InputProps={{
// endAdornment: fetching ? (
// <CircularProgress />
// ) : null,
// }}
/>
#ts snippet
const emailOnChange = debounce(function (event, id, index) {
setRoleId(id);
setEmailCurrentIndex(index);
const payload: IYardUserRequestPayload | InitialReqPaylod = {
accountId: 1,
searchString: event.target.value,
};
setFetching(true);
dispatch(getYardUser(payload));
}, 500);

Updating Antd v3 form input field with setfieldsvalue from an API response data

I'm trying to make changes to a form Input field to be read only. The value of this Input field is dependent on a Select field that a user had chosen.
Whenever a user choose an option in the Select field, an API call will be made based on the chosen value. So from these response value, I need to update the mentioned Input field.
below are the code that I wrote, the Input field didn't get update by directly using the Input's value props. I feel that I might need to use form.setFieldsValue(), but I'm not sure how to implement it in this kind scenario.
export default class onBoardForm extends Component {
constructor(props) {
super(props);
this.state = {
...
...
ocClusters: ["dasda","dasdasd","adasdasd"],
ocClusterDetails: { ocUrl: "", registry: "" },
}
}
onOcClusterChange = async (e) => {
let ocClusterDetails = await this.getOcCluster(e);
// ocClusterDetails = { ocUrl: "asdasff", registry: "dasdasdasd" }
this.setState({ ocClusterDetails });
};
...
...
render() {
...
...
<StyledFormItem
label={<span>OC Cluster</span>}>
{getFieldDecorator("ocCluster", {
rules: [
{
required: true,
message: "Please enter OC Cluster. ",
whitespace: true,
},
],
})(
<Select
disabled={this.state.occupied}
onChange={this.onOcClusterChange}
>
{this.state.ocClusters.map((ocCluster) => (
<Option value={ocCluster} key={ocCluster}>
{ocCluster}
</Option>
))}
</Select>
)}
</StyledFormItem>
<StyledFormItem
label={
<span>
OC URL
<Tooltip title="Base Url of openshift">
<Icon type="info-circle" />
</Tooltip>
</span>
}
>
{getFieldDecorator("ocUrl", {
rules: [
{
required: true,
message: "Please enter OC URL.",
whitespace: true,
},
],
})(
<Input
disabled
value={this.state.ocClusterDetails.ocUrl}
/>
)}
</StyledFormItem>
<StyledFormItem label={<span>Registry URL</span>}>
{getFieldDecorator("registry1", {
rules: [
{
required: true,
message: "Please enter Registry URL.",
whitespace: true,
},
],
})(
<Input
disabled
value={this.state.ocClusterDetails.registry}
/>
)}
...
...
}
This is my first time handling Antd library, so any input will be very helpful to me. Thank you

Get list of Fields of an Ant Design Form

I have an ant design form on React.
How can I get the whole list of fields of a form? (all of them are wrapped by Form.Item)?
When I submit a form, is there any way to find out which fields are changed(touched) and their value?
import React from 'react'
function TempForm({ form }) {
const submit = e => {
e.preventDefault()
form.validateFields((error, values) => {
if (error) {
console.log('error while validating')
} else if (values) {
console.log('name: ', values.name, 'email: ', values.email)
}
})
}
return (
<Form onSubmit={submit}>
<div>
<Form.Item label="Customer">
{form.getFieldDecorator('name', {
initialValue: 'John',
rules: [{ required: true, message: 'Please select a customer!' }],
})(<Input type="text" placeholder="name" />)}
</Form.Item>
<Form.Item label="Customer Email">
{form.getFieldDecorator('email', {
rules: [{ required: true, message: 'Please select a Clinic' }],
})(<Input type="email" placeholder="customer email" />)}
</Form.Item>
</div>
</Form>
)
}
export default Form.create()(TempForm)
Here we are having a antd-form(import all necessary components) and a on-submit function. You can easily access all you fields as shown. Here values will be a js-object containing key-value pair or you can use form.getFieldValue('name') to access form values.

How to Validate Multiple Phone Numbers with Formik Yup

I am building a form a where a user can store multiple phone numbers and set the privacy of that number (whether he wants the number to be publicly displayed or not).
I have succesfully created the form but stuck in formik-yup validation and getting the values (phone number with privacy value) to further send it to backend.
import React, { Component } from "react";
import { Formik, Form, Field, ErrorMessage, FieldArray } from "formik";
import * as Yup from "yup";
import DropDown from "./DropDown";
const phoneNumberPrivacyDropdown = [
{ value: "private", option: "Private" },
{ value: "public", option: "Public" }
];
const phoneRegExp = /^((\\+[1-9]{1,4}[ \\-]*)|(\\([0-9]{2,3}\\)[ \\-]*)|([0-9]{2,4})[ \\-]*)*?[0-9]{3,4}?[ \\-]*[0-9]{3,4}?$/; // for Mobile Numbers
export default class PhoneNumbers extends Component {
constructor(props) {
super(props);
this.state = {
phoneNumbers: [{ privacy: "", number: "" }]
};
this.addNewPhoneNumber = this.addNewPhoneNumber.bind(this);
this.removePhoneNumber = this.removePhoneNumber.bind(this);
}
addNewPhoneNumber() {
let newPhoneNumber = { privacy: "", number: "" };
this.setState({
phoneNumbers: [...this.state.phoneNumbers, newPhoneNumber]
});
}
removePhoneNumber = key => {
let phoneNumbers = this.state.phoneNumbers;
phoneNumbers.splice(key, 1);
this.setState({
phoneNumbers: phoneNumbers
});
};
render() {
return (
<div>
<h1 className="form-subHead">Multiple Phone Numbers.</h1>
<Formik
initialValues={{
phoneNumbers: this.state.phoneNumbers
}}
validationSchema={Yup.object().shape({
phoneNumbers: Yup.array().of(
Yup.object().shape({
mobile: Yup.string()
.required("Please tell us your mobile number.")
.length(10, "Please enter a valid mobile number.")
.matches(phoneRegExp, "Please enter a valid mobile number.")
})
)
})}
onSubmit={(values, { resetForm, setErrors, setSubmitting }) => {
setTimeout(() => {
console.log("Getting form values - ", values);
setSubmitting(false);
}, 500);
}}
enableReinitialize={true}
>
{props => {
const {
values,
touched,
dirty,
errors,
isSubmitting,
handleChange,
handleBlur,
setFieldValue,
setFieldTouched
} = props;
return (
<Form id="signUpForm" className="signinupForm mt-4" noValidate>
<div className="formSection">
<div className="row form-row">
<div className="col-sm-6">
<div className="form-group phoneNumberGroup">
<label htmlFor="phoneNumbers" className="form-label">
Phone Number
</label>
{this.state.phoneNumbers.map((phoneNumber, i) => (
<div className="phoneNumber" key={i}>
<Field
type="number"
name={`phone${i + 1}`}
placeholder="Contact Number"
className="form-control mobileNumber"
/>
<div className="selectPhonePrivacy">
<DropDown
items={phoneNumberPrivacyDropdown}
inputname="phonePrivacy"
showIconOnly={false}
/>
</div>
{i != 0 && (
<span
className="modifyInput removeElement"
onClick={() => this.removePhoneNumber({ i })}
>
-
</span>
)}
<ErrorMessage
name="mobile"
component="span"
className="invalid-input"
/>
</div>
))}
{this.state.phoneNumbers.length <= 2 && ( // only upto 3 phone numbers allowed!
<a
className="modifyInput addElement"
onClick={this.addNewPhoneNumber}
>
Add Another Phone
</a>
)}
</div>
{/* Phone Numbers Group */}
</div>
</div>
</div>
<div className="text-center">
<button
type="submit"
className="btn btn-filled"
disabled={!dirty || isSubmitting}
>
Finish
</button>
{/*Submit */}
</div>
</Form>
);
}}
</Formik>
</div>
);
}
}
Here is a codesandbox demo for the actual codes -
https://codesandbox.io/s/dynamic-field-validation-7t1ww

Dynamic variables in react js

i have a dynamic form in react js which gives me a output like the following -
screes are here of console logs - http://imgur.com/a/w9KYN
Object
keys
:
Array[2]
0
:
1
1
:
2
length
:
2
proto
:
Array[0]
names-1
:
"bill"
names-2
:
"wil"
noItems-1
:
50
noItems-2
:
50050
tVal-1
:
500
tVal-2
:
2520
values-1
:
500
values-2
:
500
Console.log(JSON.Stringfy(values)) -
{"keys":[1,2],"names-1":"will","values-1":200,"noItems-1":2002,"tVal-1":200,"names-2":"bill","values-2":200,"noItems-2":2002,"tVal-2":200}
if i delete one or two form items from the middle - here is the output -
{"keys":[1,4],"names-1":"will","values-1":200,"noItems-1":2002,"tVal-1":200,"names-4":"dill","values-4":300,"noItems-4":300,"tVal-4":300}
I can read the keys array in such manner -
console.log('Recived values:', values.keys);
But i want to iterate the values, Can someone help me in iterating the values? to be specific how go i get 'names-1' and 'names-2'? as the string is based on the keys array?
The code snippet is here :
hadleSubmit = (e) => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if(!err){
var lis = values.keys;
this.setState({
controlKey: lis
});
lis.forEach(function(value){
/* need help to iterate here*/
})
console.log('Recived values:', values.keys);
}
})
}
my render component looks something like this -
const {getFieldDecorator, getFieldValue} = this.props.form;
const formItemLayoutWithOutLabel = {
wrapperCol: {
xs: { span: 24, offset: 0 },
sm: { span: 20, offset: 4 },
},
};
getFieldDecorator('keys', {initialValue:[]});
const keys = getFieldValue('keys');
const formItems = keys.map((k, index) => {
return(
<div>
<Row>
<Col span={6}>
<FormItem
label={index === 0 ? 'Item' : ''}
required={false}
key={k}
>
{getFieldDecorator(`names-${k}`, {
validateTrigger: ['onChange'],
rules: [{
required: true,
whitespace: true,
message: 'Please input item name',
}],
})(
<Input placeholder="Item Name" style={{width: '75%'}}/>
)}
</FormItem>
</Col>
<Col span={6}>
<FormItem
label={index === 0 ? 'Value/Unit' : ''}
required={false}
key={k}
>
{getFieldDecorator(`values-${k}`, {
validateTrigger: ['onChange'],
rules: [{
required: true,
message: 'Please input item value',
}],
})(
<InputNumber placeholder="Item value per unit" style={{width: '75%'}}/>
)}
</FormItem>
</Col>
<Col span = {6}>
<FormItem
label={index === 0 ? 'Total Unit' : ''}
required={false}
key={k}
>
{getFieldDecorator(`noItems-${k}`, {
validateTrigger: ['onChange'],
rules: [{
required: true,
message: 'Please input total number of items',
}],
})(
<InputNumber placeholder="Please input total number of items" style={{width: '75%'}}/>
)}
</FormItem>
</Col>
<Col span={6}>
<FormItem
label={index === 0 ? 'Total Value' : ''}
required={false}
key={k}
>
{getFieldDecorator(`tVal-${k}`, {
validateTrigger: ['onChange'],
rules: [{
required: true,
message: 'Total Value',
}],
})(
<InputNumber placeholder="Total Value" style={{width: '75%'}}/>
)}
<Icon
className="dynamic-delete-button"
type="minus-circle-o"
disabled={keys.length === 1}
onClick={() => this.remove(k)}
/>
</FormItem>
</Col>
</Row>
</div>
what you want to do is define the variables to be used
const myVars = ['names', 'noItems', 'tVal', 'values']
let totalVal = 0;
lis.forEach( (value) => {
myVars.forEach( myVar => {
const key = `${myVar}-${value}`
console.log(`${key}: ${values[key]}`)
if (myVar === 'tVal') {
totalVal += values[key]
}
})
})
console.log(totalVal);
FIDDLE
so basically what i'm doing here is using the myVars array to define which keys i'm interested in. From there I am looping over the keys array to know which variable to create aka name-number. then values (the original object) bracket or sub notation on that key to get the actual value.

Categories