stormy-gold
stormy-gold4mo ago

useStepForm

if form submit has backend field errors, it is showing for current step but if back to previous step, error vanished
14 Replies
kapa.ai
kapa.ai4mo ago
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 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: ----------------------
kapa.ai
kapa.ai4mo ago
<@940119979334967366> kapa.ai is still learning and improving, please let us know how it did by reacting below
stormy-gold
stormy-goldOP4mo ago
@kapa.ai But i am using useStepForm and Form.Item from @refinedev/antd How to implement for them
kapa.ai
kapa.ai4mo ago
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:
import { Create, useSelect, useStepsForm } from "@refinedev/antd";
import { HttpError } from "@refinedev/core";
import { Button, Form, Input, Select, Steps } from "antd";
import React 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 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;
title: string;
}

interface IPost {
id: number;
title: string;
content: string;
status: "published" | "draft" | "rejected";
category: { id: number };
}
import { Create, useSelect, useStepsForm } from "@refinedev/antd";
import { HttpError } from "@refinedev/core";
import { Button, Form, Input, Select, Steps } from "antd";
import React 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 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;
title: string;
}

interface IPost {
id: number;
title: string;
content: string;
status: "published" | "draft" | "rejected";
category: { id: number };
}
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: ----------------------
kapa.ai
kapa.ai4mo ago
<@940119979334967366> kapa.ai is still learning and improving, please let us know how it did by reacting below
stormy-gold
stormy-goldOP4mo 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
kapa.ai
kapa.ai4mo ago
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 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: ----------------------
kapa.ai
kapa.ai4mo ago
<@940119979334967366> kapa.ai is still learning and improving, please let us know how it did by reacting below
stormy-gold
stormy-goldOP4mo ago
@kapa.ai onFinishFailed not called
kapa.ai
kapa.ai4mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- If 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: ----------------------
kapa.ai
kapa.ai4mo ago
<@940119979334967366> kapa.ai is still learning and improving, please let us know how it did by reacting below
stormy-gold
stormy-goldOP4mo ago
@kapa.ai Below is the cod, not able to set error for previsous page, no error generate
kapa.ai
kapa.ai4mo ago
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 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: ----------------------
kapa.ai
kapa.ai4mo ago
<@940119979334967366> kapa.ai is still learning and improving, please let us know how it did by reacting below