useStepForm
if form submit has backend field errors, it is showing for current step but if back to previous step, error vanished
14 Replies
Hi @viveksingh0143. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
----------------------
It seems like you're experiencing an issue where backend field errors are not persisting when navigating back to previous steps in a form using
import { useStepsForm } from "@refinedev/react-hook-form";
const PostCreate = () => {
const {
refineCore: { onFinish, formLoading },
register,
handleSubmit,
formState: { errors },
steps: { currentStep, gotoStep },
} = useStepsForm<IPost, HttpError, IPost>();
const { options } = useSelect<ICategory, HttpError>({
resource: "categories",
}); const renderFormByStep = (step: number) => {
switch (step) {
case 0:
return (
<>
<label>Title: </label>
<input
{...register("title", {
required: "This field is required",
})}
/>
{errors.title && <span>{errors.title.message}</span>}
</>
);
case 1:
return (
<>
<label>Status: </label>
<select {...register("status")}>
<option value="published">published</option>
<option value="draft">draft</option>
<option value="rejected">rejected</option>
</select>
</>
);
case 2:
return (
<>
<label>Category: </label>
<select
{...register("category.id", {
required: "This field is required",
})}
<option key={category.value} value={category.value}>
{category.label}
</option>
))}
</select>
{errors.category && <span>{errors.category.message}</span>}
<br />
<br />
<label>Content: </label>
<textarea
{...register("content", {
required: "This field is required",
})}
rows={10}
cols={50}
/>
{errors.content && <span>{errors.content.message}</span>}
</>
);
}
};
if (formLoading) {
return <div>Loading...</div>;
} return (
<div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
<div style={{ display: "flex", gap: 36 }}>
{stepTitles.map((title, index) => (
<button
key={index}
onClick={() => gotoStep(index)}
style={{
backgroundColor: currentStep === index ? "lightgray" : "initial",
}}
</button>
))}
</div ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
useStepsForm
. This behavior can be problematic as users might miss important validation messages.
Based on the knowledge sources provided, there isn't a direct solution to this specific issue. However, I can guide you on how to handle form errors in a multi-step form using useStepsForm
from @refinedev/react-hook-form
.
Here's a basic example of how to set up a multi-step form with error handling:
```tsx
import { HttpError, useSelect } from "@refinedev/core";import { useStepsForm } from "@refinedev/react-hook-form";
const PostCreate = () => {
const {
refineCore: { onFinish, formLoading },
register,
handleSubmit,
formState: { errors },
steps: { currentStep, gotoStep },
} = useStepsForm<IPost, HttpError, IPost>();
const { options } = useSelect<ICategory, HttpError>({
resource: "categories",
}); const renderFormByStep = (step: number) => {
switch (step) {
case 0:
return (
<>
<label>Title: </label>
<input
{...register("title", {
required: "This field is required",
})}
/>
{errors.title && <span>{errors.title.message}</span>}
</>
);
case 1:
return (
<>
<label>Status: </label>
<select {...register("status")}>
<option value="published">published</option>
<option value="draft">draft</option>
<option value="rejected">rejected</option>
</select>
</>
);
case 2:
return (
<>
<label>Category: </label>
<select
{...register("category.id", {
required: "This field is required",
})}
{options?.map((category) => (
<option key={category.value} value={category.value}>
{category.label}
</option>
))}
</select>
{errors.category && <span>{errors.category.message}</span>}
<br />
<br />
<label>Content: </label>
<textarea
{...register("content", {
required: "This field is required",
})}
rows={10}
cols={50}
/>
{errors.content && <span>{errors.content.message}</span>}
</>
);
}
};
if (formLoading) {
return <div>Loading...</div>;
} return (
<div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
<div style={{ display: "flex", gap: 36 }}>
{stepTitles.map((title, index) => (
<button
key={index}
onClick={() => gotoStep(index)}
style={{
backgroundColor: currentStep === index ? "lightgray" : "initial",
}}
{index + 1} - {title}
</button>
))}
</div ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
<@940119979334967366> kapa.ai is still learning and improving, please let us know how it did by reacting below
subsequent-cyan•4w ago
@kapa.ai But i am using useStepForm and Form.Item from @refinedev/antd
How to implement for them
Let me check the knowledge base for you. One moment! :books:
----------------------
To handle backend field errors in a multi-step form using
useStepsForm
and Form.Item
from @refinedev/antd
, you need to ensure that errors are managed and displayed correctly across different steps. Here is an example of how you can achieve this:
In this example, the gotoStep
function is used to navigate between steps, and the form errors should persist as long as they are part of the form state. Ensure that your backend error handling logic correctly sets the errors in the form state.
For more detailed information, you can refer to the useStepsForm documentation (https://refine.dev/docs/ui-integrations/ant-design/hooks/use-steps-form/#usage) and the [useSelect documentation](https://refine.dev/docs/ui-integrations/ant-design
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@940119979334967366> kapa.ai is still learning and improving, please let us know how it did by reacting below
subsequent-cyan•4w ago
@kapa.ai yes my backend error handling logic correctly sets, it shows properly on current steps, but when go to previous step, errors don't show, I also checked form state errors are coming properly
Let me check the knowledge base for you. One moment! :books:
----------------------
To ensure that backend errors persist and are displayed correctly when navigating back to previous steps in a multi-step form using
import { HttpError } from "@refinedev/core";
import { Button, Form, Input, Select, Steps } from "antd";
import React, { useEffect, useState } from "react";
const { Step } = Steps;
export const PostCreate: React.FC = () => {
const { current, gotoStep, stepsProps, formProps, saveButtonProps, query } =
useStepsForm<IPost, HttpError, IPost>();
const { selectProps: categorySelectProps } = useSelect<ICategory, HttpError>({
resource: "categories",
});
const [backendErrors, setBackendErrors] = useState<any>({});
useEffect(() => {
// Set form errors from backend errors when navigating to a step if (backendErrors[current]) {
formProps.form?.setFields(backendErrors[current]);
}
}, [current, backendErrors, formProps.form]);
const handleBackendErrors = (errors: any) => {
const newBackendErrors = { ...backendErrors };
newBackendErrors[current] = errors;
setBackendErrors(newBackendErrors);
}; const formList = [
<>
<Form.Item
label="Title"
name="title"
rules={[
{
required: true,
},
]}
</Form.Item>
</>,
<>
<Form.Item
label="Category"
name={["category", "id"]}
rules={[
{
required: true,
},
]}
</Form.Item>
</>,
];
return (
<Create saveButtonProps={saveButtonProps}>
<Steps {...stepsProps}>
<Step title="About Post" />
<Step title="Content" />
</Steps>
<Form {...formProps} layout="vertical" onFinishFailed={({ errorFields }) => handleBackendErrors(errorFields)}>
{formList[current]}
</Form>
<div style={{ marginTop: 24 }}>
{current > 0 && (
<Button
onClick={() => {
gotoStep(current - 1);
}}
</Button>
)}
{current < formList.length - 1 && (
<Button
onClick={() => {
gotoStep(current + 1);
}}
</Button>
)}
{current === formList.length - 1 && (
<Button
type="primary"
onClick={() => {
formProps.form?.submit();
}} ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
useStepsForm
and Form.Item
from @refinedev/antd
, you can manually set the errors in the form state when navigating between steps. Here’s how you can achieve this:
1. Capture Backend Errors: Ensure that backend errors are captured and stored in a state.
2. Set Errors Manually: When navigating back to a previous step, manually set the errors for that step.
Here’s an example implementation:
```tsx
import { Create, useSelect, useStepsForm } from "@refinedev/antd";import { HttpError } from "@refinedev/core";
import { Button, Form, Input, Select, Steps } from "antd";
import React, { useEffect, useState } from "react";
const { Step } = Steps;
export const PostCreate: React.FC = () => {
const { current, gotoStep, stepsProps, formProps, saveButtonProps, query } =
useStepsForm<IPost, HttpError, IPost>();
const { selectProps: categorySelectProps } = useSelect<ICategory, HttpError>({
resource: "categories",
});
const [backendErrors, setBackendErrors] = useState<any>({});
useEffect(() => {
// Set form errors from backend errors when navigating to a step if (backendErrors[current]) {
formProps.form?.setFields(backendErrors[current]);
}
}, [current, backendErrors, formProps.form]);
const handleBackendErrors = (errors: any) => {
const newBackendErrors = { ...backendErrors };
newBackendErrors[current] = errors;
setBackendErrors(newBackendErrors);
}; const formList = [
<>
<Form.Item
label="Title"
name="title"
rules={[
{
required: true,
},
]}
<Input />
</Form.Item>
</>,
<>
<Form.Item
label="Category"
name={["category", "id"]}
rules={[
{
required: true,
},
]}
<Select {...categorySelectProps} />
</Form.Item>
</>,
];
return (
<Create saveButtonProps={saveButtonProps}>
<Steps {...stepsProps}>
<Step title="About Post" />
<Step title="Content" />
</Steps>
<Form {...formProps} layout="vertical" onFinishFailed={({ errorFields }) => handleBackendErrors(errorFields)}>
{formList[current]}
</Form>
<div style={{ marginTop: 24 }}>
{current > 0 && (
<Button
onClick={() => {
gotoStep(current - 1);
}}
Previous
</Button>
)}
{current < formList.length - 1 && (
<Button
onClick={() => {
gotoStep(current + 1);
}}
Next
</Button>
)}
{current === formList.length - 1 && (
<Button
type="primary"
onClick={() => {
formProps.form?.submit();
}} ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
<@940119979334967366> kapa.ai is still learning and improving, please let us know how it did by reacting below
subsequent-cyan•4w ago
@kapa.ai onFinishFailed not called
Let me check the knowledge base for you. One moment! :books:
----------------------
If
import { HttpError } from "@refinedev/core";
import { Button, Form, Input, Select, Steps } from "antd";
import React, { useEffect, useState } from "react";
const { Step } = Steps;
export const PostCreate: React.FC = () => {
const { current, gotoStep, stepsProps, formProps, saveButtonProps, query } =
useStepsForm<IPost, HttpError, IPost>();
const { selectProps: categorySelectProps } = useSelect<ICategory, HttpError>({
resource: "categories",
});
const [backendErrors, setBackendErrors] = useState<any>({});
useEffect(() => {
// Set form errors from backend errors when navigating to a step if (backendErrors[current]) {
formProps.form?.setFields(backendErrors[current]);
}
}, [current, backendErrors, formProps.form]);
const handleBackendErrors = (errors: any) => {
const newBackendErrors = { ...backendErrors };
newBackendErrors[current] = errors;
setBackendErrors(newBackendErrors);
}; const formList = [
<>
<Form.Item
label="Title"
name="title"
rules={[
{
required: true,
},
]}
</Form.Item>
</>,
<>
<Form.Item
label="Category"
name={["category", "id"]}
rules={[
{
required: true,
},
]}
</Form.Item>
</>,
];
return (
<Create saveButtonProps={saveButtonProps}>
<Steps {...stepsProps}>
<Step title="About Post" />
<Step title="Content" />
</Steps>
<Form {...formProps} layout="vertical">
{formList[current]}
</Form>
<div style={{ marginTop: 24 }}>
{current > 0 && (
<Button
onClick={() => {
gotoStep(current - 1);
}}
</Button>
)}
{current < formList.length - 1 && (
<Button
onClick={() => {
gotoStep(current + 1);
}}
</Button>
)}
{current === formList.length - 1 && (
<Button
type="primary"
onClick={() => {
formProps.form?.submit();
}}
</Button>
)}
</div>
</Create>
);
};
interface ICategory {
id: number; ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
onFinishFailed
is not being called, you can manually handle backend errors and set them in the form state when navigating between steps. Here’s how you can achieve this:
1. Capture Backend Errors: Ensure that backend errors are captured and stored in a state.
2. Set Errors Manually: When navigating back to a previous step, manually set the errors for that step.
Here’s an example implementation:
```tsx
import { Create, useSelect, useStepsForm } from "@refinedev/antd";import { HttpError } from "@refinedev/core";
import { Button, Form, Input, Select, Steps } from "antd";
import React, { useEffect, useState } from "react";
const { Step } = Steps;
export const PostCreate: React.FC = () => {
const { current, gotoStep, stepsProps, formProps, saveButtonProps, query } =
useStepsForm<IPost, HttpError, IPost>();
const { selectProps: categorySelectProps } = useSelect<ICategory, HttpError>({
resource: "categories",
});
const [backendErrors, setBackendErrors] = useState<any>({});
useEffect(() => {
// Set form errors from backend errors when navigating to a step if (backendErrors[current]) {
formProps.form?.setFields(backendErrors[current]);
}
}, [current, backendErrors, formProps.form]);
const handleBackendErrors = (errors: any) => {
const newBackendErrors = { ...backendErrors };
newBackendErrors[current] = errors;
setBackendErrors(newBackendErrors);
}; const formList = [
<>
<Form.Item
label="Title"
name="title"
rules={[
{
required: true,
},
]}
<Input />
</Form.Item>
</>,
<>
<Form.Item
label="Category"
name={["category", "id"]}
rules={[
{
required: true,
},
]}
<Select {...categorySelectProps} />
</Form.Item>
</>,
];
return (
<Create saveButtonProps={saveButtonProps}>
<Steps {...stepsProps}>
<Step title="About Post" />
<Step title="Content" />
</Steps>
<Form {...formProps} layout="vertical">
{formList[current]}
</Form>
<div style={{ marginTop: 24 }}>
{current > 0 && (
<Button
onClick={() => {
gotoStep(current - 1);
}}
Previous
</Button>
)}
{current < formList.length - 1 && (
<Button
onClick={() => {
gotoStep(current + 1);
}}
Next
</Button>
)}
{current === formList.length - 1 && (
<Button
type="primary"
onClick={() => {
formProps.form?.submit();
}}
Submit
</Button>
)}
</div>
</Create>
);
};
interface ICategory {
id: number; ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
<@940119979334967366> kapa.ai is still learning and improving, please let us know how it did by reacting below
subsequent-cyan•4w ago
@kapa.ai Below is the cod, not able to set error for previsous page, no error generate
Let me check the knowledge base for you. One moment! :books:
----------------------
To ensure that backend errors persist and are displayed correctly when navigating back to previous steps in a multi-step form using
import { HttpError } from "@refinedev/core";
import { Button, Form, Input, Select, Steps } from "antd";
import React, { useEffect, useState } from "react";
const { Step } = Steps;
export const PostCreate: React.FC = () => {
const { current, gotoStep, stepsProps, formProps, saveButtonProps, query } =
useStepsForm<IPost, HttpError, IPost>();
const { selectProps: categorySelectProps } = useSelect<ICategory, HttpError>({
resource: "categories",
});
const [backendErrors, setBackendErrors] = useState<any>({});
useEffect(() => {
// Set form errors from backend errors when navigating to a step if (backendErrors[current]) {
formProps.form?.setFields(backendErrors[current]);
}
}, [current, backendErrors, formProps.form]);
const handleBackendErrors = (errors: any) => {
const newBackendErrors = { ...backendErrors };
newBackendErrors[current] = errors;
setBackendErrors(newBackendErrors);
}; const formList = [
<>
<Form.Item
label="Title"
name="title"
rules={[
{
required: true,
},
]}
</Form.Item>
</>,
<>
<Form.Item
label="Category"
name={["category", "id"]}
rules={[
{
required: true,
},
]}
</Form.Item>
</>,
];
return (
<Create saveButtonProps={saveButtonProps}>
<Steps {...stepsProps}>
<Step title="About Post" />
<Step title="Content" />
</Steps>
<Form {...formProps} layout="vertical">
{formList[current]}
</Form>
<div style={{ marginTop: 24 }}>
{current > 0 && (
<Button
onClick={() => {
gotoStep(current - 1);
}}
</Button>
)}
{current < formList.length - 1 && (
<Button
onClick={() => {
gotoStep(current + 1);
}}
</Button>
)}
{current === formList.length - 1 && (
<Button
type="primary"
onClick={() => {
formProps.form?.submit();
}}
</Button>
) ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
useStepsForm
and Form.Item
from @refinedev/antd
, you can manually set the errors in the form state when navigating between steps. Here’s how you can achieve this:
1. Capture Backend Errors: Ensure that backend errors are captured and stored in a state.
2. Set Errors Manually: When navigating back to a previous step, manually set the errors for that step.
Here’s an example implementation:
```tsx
import { Create, useSelect, useStepsForm } from "@refinedev/antd";import { HttpError } from "@refinedev/core";
import { Button, Form, Input, Select, Steps } from "antd";
import React, { useEffect, useState } from "react";
const { Step } = Steps;
export const PostCreate: React.FC = () => {
const { current, gotoStep, stepsProps, formProps, saveButtonProps, query } =
useStepsForm<IPost, HttpError, IPost>();
const { selectProps: categorySelectProps } = useSelect<ICategory, HttpError>({
resource: "categories",
});
const [backendErrors, setBackendErrors] = useState<any>({});
useEffect(() => {
// Set form errors from backend errors when navigating to a step if (backendErrors[current]) {
formProps.form?.setFields(backendErrors[current]);
}
}, [current, backendErrors, formProps.form]);
const handleBackendErrors = (errors: any) => {
const newBackendErrors = { ...backendErrors };
newBackendErrors[current] = errors;
setBackendErrors(newBackendErrors);
}; const formList = [
<>
<Form.Item
label="Title"
name="title"
rules={[
{
required: true,
},
]}
<Input />
</Form.Item>
</>,
<>
<Form.Item
label="Category"
name={["category", "id"]}
rules={[
{
required: true,
},
]}
<Select {...categorySelectProps} />
</Form.Item>
</>,
];
return (
<Create saveButtonProps={saveButtonProps}>
<Steps {...stepsProps}>
<Step title="About Post" />
<Step title="Content" />
</Steps>
<Form {...formProps} layout="vertical">
{formList[current]}
</Form>
<div style={{ marginTop: 24 }}>
{current > 0 && (
<Button
onClick={() => {
gotoStep(current - 1);
}}
Previous
</Button>
)}
{current < formList.length - 1 && (
<Button
onClick={() => {
gotoStep(current + 1);
}}
Next
</Button>
)}
{current === formList.length - 1 && (
<Button
type="primary"
onClick={() => {
formProps.form?.submit();
}}
Submit
</Button>
) ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
<@940119979334967366> kapa.ai is still learning and improving, please let us know how it did by reacting below