I am new to ant design. I have a form with two date pickers. Issue date and expiry date. I want to be able to limit the date picker for the expiry date to not be earlier than the issue date. This is my approach so far.
<Form.Item
label="Issue Date"
name={["userIdentification", "identification_issue_date"]}
rules={[
{
required: true,
message: REQUIRED_ERROR_MESSAGE,
},
]}
>
<DatePicker
disabledDate={(current) =>
current && current > moment()
}
/>
</Form.Item>
<Form.Item
label="Expiry Date"
name={[
"userIdentification",
"identification_expiry_date",
]}
dependencies={[
"userIdentification",
"identification_issue_date",
]}
rules={[
{
required: true,
message: REQUIRED_ERROR_MESSAGE,
},
({ getFieldValue }) => ({
validator(_, value) {
console.log(
"fields value from issue_date",
getFieldValue([
"userIdentification",
"identification_issue_date",
])
);
if (!value && getFieldValue("allocation") === "") {
return Promise.reject(REQUIRED_ERROR_MESSAGE);
}
return Promise.resolve();
},
}),
]}
>
<DatePicker
disabledDate={(current) =>
current && current > moment()
}
/>
</Form.Item>
Any help would be greatly appreaciated
As you can read on this forum
the best solution found is to use disableDate
and add this code
<DatePicker value={value} onChange={this.onDatePickerChange} disabledDate={d => !d || d.isBefore(minimum)} />
Another way to do that could be adding something like a minDate with a similar process as above. You can read more here
Related
I'm using react-hook-form.
What I wanna do is to push a value to an array and
validate the length of value.
This is defaultValue.
defaultValues: {
title: '',
role: '',
language: {source: '', target: []},
industry: '',
due_at: '',
content: '',
},
and this is input field that handles language.target.
<Controller
name="language.target"
control={control}
rules={{
required: true,
setValues: (v) => setValue([...getValues('language.target'), v.value]),
validate: (value) => {
return '';
},
}}
render={({field: {onChange}}) => (
<Select
options={languageIndex}
onChange={(value) => onChange(value.value)}
value={languageIndex.filter(
(item) => item.value === getValues('language.target')
)}
placeholder="Select"
/>
)}
/>
I tried this way to push a value like below and they didn't work..
setValues: (v) => setValue([...getValues('language.target'), v.value]),
setValues: (v) => [...getValues('language.target'), v.value],
also I have no idea how to validate the length of array.
If language.target.length is greater then 3,
I want to make it stop to set value.
If there's any good idea, please share with me! Thanks.
Im tried to do some calculate part for my react ant design 4 table, i don't have idea for how to get when i entered value after get automatically calculate total and then submit. any onw know how to do that correctly.
Thanks
stack blitz here
This is my code part
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
render: text => <a>{text}</a>,
},
{
title: 'Book',
dataIndex: 'book',
key: 'book',
},
{
title: 'Pen',
dataIndex: 'pen',
key: 'pen',
},
{
title: 'Tools',
key: 'tools',
dataIndex: 'tools',
},
{
title: 'Total',
key: 'total',
dataIndex: 'total',
},
];
const data = [
{
key: '1',
name: 'John Brown',
book: <Form.Item name="book1" rules={[{required: true, message: " is required"}]}><Input style={{width: 150}}/></Form.Item>,
pen: <Form.Item name="oen1" rules={[{required: true, message: "is required"}]}><Input style={{width: 150}}/></Form.Item>,
tools: <Form.Item name="tools1" rules={[{required: true, message: " is required"}]}><Input style={{width: 150}}/></Form.Item>,
total:'00000'
},
];
const onFinish = values => {
console.log(values);
};
ReactDOM.render(
<div>
<Form name="control-hooks" onFinish={onFinish}>
<Table columns={columns} dataSource={data} />
<div>
<Form.Item>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</div>
</Form>
</div>, document.getElementById('container'));
I assumed the rows can be more than one. You can achieve this by:
You need a state. In react, in order to change something on the UI (e.g. total column) you need a state. Put your data array in state.
const [data, setData] = useState([ ... ])
You need to know which row the input was when you type in. You may add some distinction on input that is equal to row key. Here I suggest to put some number on the name of input:
<Form.Item name="book-1">...</Form.Item>
<Form.Item name="pen-1">...</Form.Item>
<Form.Item name="tools-1">...</Form.Item>
Use onValuesChange prop of the <Form> it triggers every time you type on the inputs and return the form values. With this, you can extract the number on input name and use that as a reference to know which row is about to change and perform setState.
I also suggest to use InputNumber instead of Input if you only need a number input.
Here is the working link. You can start/play around there if I did not hit what you want.
You may also look on antd table editable rows. This might be easiest to use than this
I have an antd Modal, i am trying to validate a field and provided validation to it. How can i enable/disable the Ok button based on the validation. If the validation is successful then button should be enabled else disabled.
<Form>
<Modal
title={modalHeader}
okText="ADD FIELD"
cancelText="CANCEL"
visible={visible}
onCancel={onCancelHandler}
onOk={() => onAddFieldHandler(fieldName)}
width={600}
okButtonProps={{disabled:true}}
>
<p>Please provide name</p>
<Form.Item
name="fieldName"
rules={[{ required: true, message: 'Please enter name' }]}
>
<FieldNameInput
placeholder="Field name..."
value={fieldName}
onChange={(event) => setFieldName(event.target.value)}
/>
</Form.Item>
</Modal>
</Form>
You can use onFieldsChange from Antd Forms API togehter with geFieldsError and the okButtonProps from Antd Modal API.
const [form] = Form.useForm();
const [buttonDisabled, setButtonDisabled] = useState(true);
return (
<Modal
...
okButtonProps={{ disabled: buttonDisabled }}
>
<Form
form={form}
...
onFieldsChange={() =>
setButtonDisabled(
form.getFieldsError().some((field) => field.errors.length > 0)
)
}
>
Here is a working Stackblitz.
In my case I had Form inside modal and there is onFieldChange prop when you can pass function to perform some operations due to changes on from so you can sth like that:
const SomeModal = ({ visible }) => {
const [form] = Form.useForm();
const [buttonDisabled, setButtonDisabled] = useState(true);
const handleOk = () => form.submit();
const handleAfterClose = () => {
setButtonDisabled(true);
form.resetFields();
}
const handleCancel = () => ...some action to hide modal;
const handleFormFinish = (values) => {
... some logic here
}
return (
<Modal
title={"Some title..."}
visible={visibile}
onOk={handleOk}
onCancel={handleCancel}
afterClose={handleAfterClose}
okButtonProps={{ disabled: buttonDisabled }}
>
<Form
form={form}
layout="vertical"
name="acceptform"
onFinish={handleFormFinish}
initialValues={{
...initial values here
}}
onFieldsChange={() => {
const actualFieldValues = form.getFieldsValue();
const anyError = form.getFieldsError().some((field) => field.errors.length > 0);
.. some logic if error etc..
if (anyError) {
setButtonDisabled(true);
}
else {
setButtonDisabled(false);
}
}}
>
and of course there is need to have some validators on fields
<Form.Item
label={"someLabel"}
id="field"
name="field"
hasFeedback
rules={[
{
type: "string",
validator: async (rule, value) => inputFieldValidate(value, "custom message")
},
]}
>
and validator looks alike:
const inputFieldValidate = async (value, message) => {
if (someCondition)) {
return Promise.reject(message);
}
return Promise.resolve();
};
here is some nice to know that validator isasync and to make it work without any warnings just handle promises
Having the Form inside the Modal, a way to update modal button status would be just running form instance's validateFields, but there are two things to take into account:
This function is a Promise, so the state must update after an await with the validation results.
I've experienced some looping issues when using onFieldsChange (maybe the validation triggers some kind of field update). Instead, onValuesChange has worked good enough for me.
Running the validation into a setTimeout callback seems to be mandatory. Doing it without the setTimeout returns a validation error even when all the fields are valid because of an outOfDate: true. It seems to be because of how the Antd Form update lifecycle works, and waiting until this process has ended (what we can easily achieve with the setTimeout) solves that problem.
A succesful validation returns the form values object, a failed one returns an errorInfo object with the errors list, the outOfDate status and the current form values. You can use the errors list in the latter to get the validation messages returned by Antd to display more descriptive and specific feedback.
In the end, my approach has this structure:
const MyModal = ({onFinish, ...otherProps}) => {
const [canSubmit, setCanSubmit] = useState(false);
const [form] = Form.useForm();
return (
<Modal
{...otherProps}
okButtonProps={{
disabled: !canSubmit
}}
>
<MyFormComponent
form={form}
onFinish={onFinish}
onValuesChange={() => {
setTimeout(() => {
form
.validateFields()
.then(() => {
/*
values:
{
username: 'username',
password: 'password',
}
*/
setCanSubmit(true);
})
.catch((err) => {
/*
errorInfo:
{
values: {
username: 'username',
password: 'password',
},
errorFields: [
{ name: ['password'], errors: ['Please input your Password!'] },
],
outOfDate: false,
}
*/
setCanSubmit(false);
});
});
}}
/>
</Modal>
);
};
I want to trigger the validation only for input "blur" instead of typing on it. So I have used the method validateTrigger:'onBlur' and its worked fine for me as expected. After user focus/click again the input, the validation message should disappear, any solution?
<FormItem>
{getFieldDecorator('email', {
rules: [
{
type: 'email', message: 'Valid E-mail required!',
},
{ required: true, message: 'E-mail required!', whitespace:true }
],
validateTrigger:'onBlur'
})(
<Input
placeholder="Email"
/>
)}
This can be done by using ant design validateStatus parameter. You can dynamically change the statuses from given sets, i.e, 'success', 'warning', 'error', 'validating'.
validateStatus: validate status of form components which could be 'success', 'warning', 'error', 'validating'.
You need to functions, one onBlur and other onFocus. FormItem can be written as:
<FormItem
validateStatus={this.state.showError && userNameError ? "error" : ""}
help={
this.state.showError && userNameError
? "Valid E-mail required!"
: ""
}
>
{getFieldDecorator("userName", {
validateTrigger: "onBlur",
rules: [
{ type: "email", message: "Valid E-mail required!" },
{ required: true, message: "Please input your username!" }
]
})(
<Input
placeholder="Email"
onBlur={this.handleBlur}
onFocus={this.handleFocus}
/>
)}
</FormItem>
And the two methods can be written as:
handleBlur = e => {
this.setState({ showError: true });
};
handleFocus = e => {
this.setState({ showError: false });
};
Working demo is on codesandbox.io.
A form field has many asynchronous check rules, since a composited api can check these rules one time by return different result, i do not want to fire so many api request.
the syntax is updated in v4
new syntax is:
setFields. | Set fields status | (fields: FieldData[]) => void
example :
form.setFields([
{
name: 'field-to-update',
errors: ['error-string'],
},
]);
Use form.setFields
Syntax
Function({ fieldName: { value: any, errors: Error } })
Example from here -
this.props.form.setFields({
user: {
value: values.user,
errors: [new Error('forbid ha')],
},
});
When you need to add a custom error message just use validateStatus && help attributes.
For example, you've got an error as loginError (string) in your props:
<Form.Item
{ ...props.loginError && {
help: props.loginError,
validateStatus: 'error',
}}>
{getFieldDecorator('email', {
rules: [
{ required: true, message: 'You have to write the email' },
],
})(
<Input size="large"/>,
)}
</Form.Item>
form.setFields([
{
name: "email", // required
value: "myemail##gmail.com",//optional
errors: ["Invalid email"],
},
]);
I used it in v4.16.11