Reputation: 1255
How could I disable form submit button using antd
Form validations work, but I need to visually disable form submit button when validation fails
This is a stackblitz url https://stackblitz.com/edit/react-ts-z5d6tr?file=Hello.tsx
Upvotes: 16
Views: 31237
Reputation: 7067
I have handled this way
const [formError, setFormError] = useState(false);
const onValuesChange = async (values: any) => {
try {
await form.validateFields();
setFormError(false);
} catch (err) {
setFormError(true);
}
}
<Form onValuesChange={onValuesChange} > </Form>
<Button type="primary" size="large" htmlType="submit" disabled={!form.isFieldsTouched() || formError}>Save</Button>
you can also use !form.isFieldsTouched(true)
Working example: https://github.com/Aravin/Invoice-Nest/blob/main/code/client/component/Invoice/InvoiceForm.tsx#L451
This worked for me!
Upvotes: 0
Reputation: 1
I have a good solution without any additional re-render(re-evaluated) cost!! I control button component with Form.Item because it passes the Value prop to the button and when the button props changed React re-evaluate that, so if we use this Value prop inside the button for disabling and enabling, the problem will be solved!! for example:
<Form
name="form"
form={form}
initialValues={{
button: 1,
}}
onFieldsChange={() => {
// button field value = true if there isn't an error
form.setFieldValue(
"button",
//Attention: put all fields except the button field
!form.isFieldsTouched(["input"], true) ||
form.getFieldsError().filter(({ errors }) => {
return errors.length;
}).length > 0
);
}}
>
<Form.Item
name="input"
rules={[
{
required: true,
},
]}
>
<Input />
</Form.Item>
<Form.Item name="button">
<CustomButton>login</CustomButton>
</Form.Item>
</Form>
function CustomButton({children, ...rest}) {
return (
<Button
{...rest}
disabled={rest.value}
>
{children}
</Button>
);
Upvotes: 0
Reputation: 7067
This solution works for me!
const [formError, setFormError] = useState(false);
...
...
const onValuesChange = async (values: any) => {
try {
await form.validateFields();
setFormError(false);
} catch (err) {
setFormError(true);
}
}
...
...
<Form form={form} onValuesChange={onValuesChange} />
...
...
<Form.Item label="First Name" name='firstName' required={true} rules={[{ required: true, min: 3, max: 50,
message: 'First name is required, min 3 and max 50 characters!' }]}>
<Input />
</Form.Item>
...
...
<Button disabled={formError}>Save</Button>
</Form>
Upvotes: 0
Reputation: 4280
I'm going to paste here my solution in case anyone finds it useful.
Note; this solution uses the hook Form.useForm()
and the callback onFieldsChange
.
The validation is not included in this excerpt. But the idea is that when the form changes (any field) it will set the submit button (in this case inside the Modal) to disabled/enabled.
const LoginForm = () => {
const [form] = useForm();
const [disabledSave, setDisabledSave] = useState(true);
const handleFormChange = () => {
const hasErrors = form.getFieldsError().some(({ errors }) => errors.length);
setDisabledSave(hasErrors);
}
return (
<Modal okButtonProps={{ disabled: disabledSave }} onOk={form.submit}>
<Form onFieldsChange={handleFormChange} form={form}>
<Item name="username" label="username">
<Input />
</Item>
<Item name="password" label="password">
<Input />
</Item>
</Form>
</Modal>
)
};
Upvotes: 18
Reputation: 296
I found a nice solution here that doesn't involve any additional state. If you wrap your submit button in a Form.Item
like this, it should disable it until all required fields are completed. The rest of the form would remain the same.
<Form.Item
noStyle
shouldUpdate
>
{({ getFieldsValue }) => {
const { username, password } = getFieldsValue();
const formIsComplete = !!username && !!password;
return (
<Button
type="primary"
htmlType="submit"
disabled={!formIsComplete}
>
Log In
</Button>
);
}}
</Form.Item>
Upvotes: 8
Reputation: 472
import { UnlockOutlined, UserOutlined } from "@ant-design/icons";
import { Button, Card, Form, Input, Layout, Space } from "antd";
import { ValidateErrorEntity } from "rc-field-form/es/interface";
import React, { useState } from "react";
import "antd/dist/antd.css";
interface LoginForm {
username: string;
password: string;
}
const Hello = () => {
// Create State
const [error, setError] = useState(false);
const onFinish = (values: LoginForm) => {
};
const onFinishFailed = (errorInfo: ValidateErrorEntity) => {
setError(errorInfo); // set the state if error
};
// When the user starts type set state to false
const handleChange = e => e.target.value && setError(false);
return (
<Layout className="login">
<Card className="card">
<Form
onFinish={onFinish}
onFinishFailed={onFinishFailed}
size="large"
layout="vertical"
>
<Space direction="vertical" size="middle">
<Form.Item
name="username"
rules={[
{ required: true, message: "Please input your username!" }
]}
>
{/*Listening to change event*/ }
<Input onChange={handleChange} prefix={<UserOutlined />} placeholder="Username" />
</Form.Item>
<Form.Item
name="password"
rules={[
{ required: true, message: "Please input your password!" }
]}
>
{/*Listening to change event*/ }
<Input.Password
onChange={handleChange}
prefix={<UnlockOutlined />}
placeholder="Password"
/>
</Form.Item>
<Form.Item className="submit">
{/*Disable button only if error is true*/ }
<Button disabled={error && true} type="primary" htmlType="submit">
Login
</Button>
</Form.Item>
</Space>
</Form>
</Card>
</Layout>
);
};
export default Hello;
Upvotes: 0
Reputation: 1255
I found some elegant way to perform this
<Form.Item shouldUpdate className="submit">
{() => (
<Button
type="primary"
htmlType="submit"
disabled={
!form.isFieldsTouched(true) ||
form.getFieldsError().filter(({ errors }) => errors.length)
.length > 0
}
>
Log in
</Button>
)}
</Form.Item>
Upvotes: 27
Reputation: 2292
I did some edits here : https://stackblitz.com/edit/react-ts-spuhdd?file=Hello.tsx
Sum up of what I've done :
Upvotes: -1