Get list of Fields of an Ant Design Form - javascript

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.

Related

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

How to add object to react-final-form field name dynamically?

This react-final-form component will return the following result
<Field
name="answers[0].name"
component="input"
type="radio"
value="0"
/>
{ answers: [ { name: 'value' } ] }
How to add another property? that will end like This
{ answers: [ { name: 'user input value will here', other: 'my custom data' } ] }
According to final-form you can name your field component in 4 ways
You can add an initialValues prop to the form which will pre-populate the result.
<Form
onSubmit={onSubmit}
initialValues={{
answers: [ { other: 'your custom data' } ]
}}
>
<Field
name="answers[0].name"
component="input"
type="text"
/>
</Form>

How to display the error message (from the response of server) on the right or below the username inputt field?

I implement authorization and registration in the application using Fomik and Yup.
But if I register the user which have usernamewas already registered on my server, my local server gives me message error. And that's right. I need it.
Where and when I'm getting an error message:
After I wrote in all input fields(including a username who is already registered)and I press button submit then I click in my browser Ctrl + shift + I then the tab Network, then I click file request and tabs Response and there I see this:
[{"message":"User with this username already exists","field":"username","validation":"unique"}]
screenshot of image hosting:
http://i.piccy.info/i9/24c98548e2e83f9592c62560e7f3ab2d/1586694052/96796/1372209/ddd.png
Then what do I need:
I need that message error:
User with this username already exists
displayed to the right of or below the username input field.
What to add to the files myForm.js or in SignInput.js to display the error message(Network tabs on browser/Response) on the right or below the username input field?
some part of myForm.js:
const myForm = () => {
const history = useHistory();
const {handleSubmit, values, handleChange, errors, handleBlur} = useFormik({
initialValues: {
username: '',
password: '',
/............
},
validateOnBlur: false,
validateOnchange: false,
validationSchema: yup.object().shape({
username: yup.string()
.required('This field is required'),
password: yup.string()
.required('This field is required')
.min(6, 'This password is too short')
.max(30, 'This passwors is too long'),
/..........
}),
onSubmit: async (formValues) => {
try {
const res = await api('api/auth/register', {
method:'POST',
body: JSON.stringify(formValues)
});
const token = res.token.token;
localStorage.setItem('myToken', token);
history.push("/home");
} catch(e) {
console.error(e);
}
},
});
return (
<form onSubmit={handleSubmit}>
<SignupInput
label="username"
id="username"
inputProps={{
name:'username',
value: values.username,
onChange: handleChange,
onBlur: handleBlur,
}}
error={errors.username}
/>
<SignupInput
label="password"
id="password"
inputProps={{
name:'password',
value: values.password,
onChange: handleChange,
onBlur: handleBlur,
type:'password'
}}
error={errors.password}
/>
/.............
<button type="submit" disabled={isSubmitting}>Submit Form</button>
</form>
);
};
Also I write file SignupInput.js(where SignupInput component):
const SignupInput = ({
label, inputProps, error, id,
}) => (
<div className="ffinput">
<label htmlFor={id} className="ffinput-label">
{label}
</label>
<input {...inputProps} id={id} />
{error && <span className="ffinput-error">{error}</span>}
</div>
);
SignupInput.propTypes = {
label: PropTypes.string.isRequired,
inputProps: PropTypes.instanceOf(Object).isRequired,
error: PropTypes.string,
id: PropTypes.string.isRequired,
};
SignupInput.defaultProps = {
error: '',
}
You can get that validation error in catch block where you did console.error(e). See what object it returns by consoling e which is your error object and then store it in state by selecting appropriate property from that error object/message and pass that state to your input prop.
Now since you are already passing that formik error in the SignupInput component, you now have to pass that error logically with along with formik errors. Like errors={errors.password || backendErrorState}. Or alternative way is to show it somewhere else like on the top in a separate div/component.

how to add dynamic validation in form using reactjs

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"
/>
)}

Enzyme/ReactJS: How to find specific child component

I am trying to do a enzyme/jest unit test for a component. I need to simulate a change event of a specific child component (as there are two of them).
const wrapper = shallow(<CreateAccount />)
wrapper.find({ name: 'username' }).simulate('change', { target: { value: 'Username' } })
wrapper.find({ password: 'password' }).simulate('change', { target: { value: 'Password' } })
const state = wrapper.instance().state
expect(state).toEqual({ username: 'Username', password: 'Password' })
But this is not the correct way to find both Input components...
This is how my render() function of my component looks like:
render () {
return (
<Form onSubmit={this._onSubmit.bind(this)}>
<Input
value={this.state.description}
onChange={this._onChange.bind(this)}
name='username'
type='text'
placeholder='Username'
/>
<Input
value={this.state.url}
onChange={this._onChange.bind(this)}
name='password'
type='password'
placeholder='Password'
/>
<Button type='submit'>
Submit
</Button>
</Form>
)
In general find() returns an array so you have to use at(index) or first() to access specific element:
http://airbnb.io/enzyme/docs/api/ShallowWrapper/at.html
http://airbnb.io/enzyme/docs/api/ShallowWrapper/first.html
In your case you can also import Input component and find them like this:
import Input from 'input-component-path'
...
wrapper.find(Input).at(0).simulate('change', { target: { value: 'Username' } })
wrapper.find(Input).at(1).simulate('change', { target: { value: 'Password' } })

Categories