xenial-black
xenial-black4mo ago

Create or Edit components passes empty object {} for relations if their value is not provided

<Form.Item
label={"Category"}
name={["category", "id"]}
initialValue={formProps.initialValues?.category?.id}
>
<Select {...categorySelectProps} />
</Form.Item>
<Form.Item
label={"Brand"}
name={["brand", "id"]}
initialValue={formProps.initialValues?.category?.id}
>
<Select {...brandSelectProps} />
</Form.Item>
<Form.Item
label={"Category"}
name={["category", "id"]}
initialValue={formProps.initialValues?.category?.id}
>
<Select {...categorySelectProps} />
</Form.Item>
<Form.Item
label={"Brand"}
name={["brand", "id"]}
initialValue={formProps.initialValues?.category?.id}
>
<Select {...brandSelectProps} />
</Form.Item>
With this code, it posts below data
{
"title": "test1",
"sku": "TEST123",
"price": 45,
"description": "asd",
"category": {},
"brand": {}
}
{
"title": "test1",
"sku": "TEST123",
"price": 45,
"description": "asd",
"category": {},
"brand": {}
}
TypeORM is not able to process empty objects when they are lack of id property for create and edit
5 Replies
kapa.ai
kapa.ai4mo ago
Hi @Onder. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- To address the issue where the Create or Edit components pass empty objects {} for relations if their value is not provided, you can ensure that the form does not include these fields in the submission if they are empty. This can be achieved by conditionally including the fields based on their values. Here's how you can modify your code to handle this: 1. Check for the presence of the id before including the field in the form submission. 2. Use the onFinish handler to filter out empty objects before submitting the form data. Here is an example of how you can achieve this:
import React from "react";
import { Form, Input, Select, Button } from "antd";
import { useForm } from "@refinedev/react-hook-form";
import { useSelect } from "@refinedev/core";

const PostEdit: React.FC = () => {
const { formProps, saveButtonProps, query } = useForm<IPost>({
warnWhenUnsavedChanges: true,
});

const postData = query?.data?.data;
const { selectProps: categorySelectProps } = useSelect<ICategory>({
resource: "categories",
defaultValue: postData?.category?.id,
});
const { selectProps: brandSelectProps } = useSelect<IBrand>({
resource: "brands",
defaultValue: postData?.brand?.id,
});

const onFinish = (values: any) => {
// Filter out empty objects
if (!values.category?.id) {
delete values.category;
}
if (!values.brand?.id) {
delete values.brand;
}
// Submit the form with filtered values
formProps.onFinish(values);
};
return (
<Form {...formProps} layout="vertical" onFinish={onFinish}>
<Form.Item
label="Title"
name="title"
rules={[{ required: true }]}
>
<Input />
</Form.Item>
<Form.Item
label="Category"
name={["category", "id"]}
initialValue={formProps.initialValues?.category?.id}
>
<Select {...categorySelectProps} />
</Form.Item>
<Form.Item
label="Brand"
name={["brand", "id"]}
initialValue={formProps.initialValues?.brand?.id}
>
<Select {...brandSelectProps} />
</Form.Item>
<Button type="primary" {...saveButtonProps}>
Save
</Button>
</Form>
);
};

export default PostEdit;
import React from "react";
import { Form, Input, Select, Button } from "antd";
import { useForm } from "@refinedev/react-hook-form";
import { useSelect } from "@refinedev/core";

const PostEdit: React.FC = () => {
const { formProps, saveButtonProps, query } = useForm<IPost>({
warnWhenUnsavedChanges: true,
});

const postData = query?.data?.data;
const { selectProps: categorySelectProps } = useSelect<ICategory>({
resource: "categories",
defaultValue: postData?.category?.id,
});
const { selectProps: brandSelectProps } = useSelect<IBrand>({
resource: "brands",
defaultValue: postData?.brand?.id,
});

const onFinish = (values: any) => {
// Filter out empty objects
if (!values.category?.id) {
delete values.category;
}
if (!values.brand?.id) {
delete values.brand;
}
// Submit the form with filtered values
formProps.onFinish(values);
};
return (
<Form {...formProps} layout="vertical" onFinish={onFinish}>
<Form.Item
label="Title"
name="title"
rules={[{ required: true }]}
>
<Input />
</Form.Item>
<Form.Item
label="Category"
name={["category", "id"]}
initialValue={formProps.initialValues?.category?.id}
>
<Select {...categorySelectProps} />
</Form.Item>
<Form.Item
label="Brand"
name={["brand", "id"]}
initialValue={formProps.initialValues?.brand?.id}
>
<Select {...brandSelectProps} />
</Form.Item>
<Button type="primary" {...saveButtonProps}>
Save
</Button>
</Form>
);
};

export default PostEdit;
In this example, the onFinish handler checks if the category and brand fields have an id before including them in the form submission. If the id is not present, the field is deleted from the submission data. This approach ensures that empty objects are not sent to the server, which should resolve the issue with TypeORM not being able to process empty objects. For more information, you can refer to the refine documentation on forms and relationships (https://refine.dev/docs/guides-concepts/forms/#relationships-). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4mo ago
<@238969575289389057> kapa.ai is still learning and improving, please let us know how it did by reacting below
xenial-black
xenial-blackOP4mo ago
@kapa.ai if you don't provide category or brand object, it can process the entity and insert. but if you provide an object for them you have to provide id property. but luckily you can pass null to those id properties and that also works fine. so i did initialValue={null} for the category.id and brand.id fields
kapa.ai
kapa.ai4mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- To handle the scenario where you need to ensure that the category and brand objects are either provided with an id or set to null, you can set the initialValue to null for the category.id and brand.id fields. This way, if no value is provided, the fields will be set to null, which TypeORM can process correctly. Here's how you can modify your code to set initialValue to null for the category.id and brand.id fields:
import React from "react";
import { Form, Input, Select, Button } from "antd";
import { useForm } from "@refinedev/react-hook-form";
import { useSelect } from "@refinedev/core";

const PostEdit: React.FC = () => {
const { formProps, saveButtonProps, query } = useForm<IPost>({
warnWhenUnsavedChanges: true,
});

const postData = query?.data?.data;
const { selectProps: categorySelectProps } = useSelect<ICategory>({
resource: "categories",
defaultValue: postData?.category?.id,
});
const { selectProps: brandSelectProps } = useSelect<IBrand>({
resource: "brands",
defaultValue: postData?.brand?.id,
});

const onFinish = (values: any) => {
// Filter out empty objects
if (!values.category?.id) {
values.category = null;
}
if (!values.brand?.id) {
values.brand = null;
}
// Submit the form with filtered values
formProps.onFinish(values);
};
return (
<Form {...formProps} layout="vertical" onFinish={onFinish}>
<Form.Item
label="Title"
name="title"
rules={[{ required: true }]}
>
<Input />
</Form.Item>
<Form.Item
label="Category"
name={["category", "id"]}
initialValue={null}
>
<Select {...categorySelectProps} />
</Form.Item>
<Form.Item
label="Brand"
name={["brand", "id"]}
initialValue={null}
>
<Select {...brandSelectProps} />
</Form.Item>
<Button type="primary" {...saveButtonProps}>
Save
</Button>
</Form>
);
};

export default PostEdit;
import React from "react";
import { Form, Input, Select, Button } from "antd";
import { useForm } from "@refinedev/react-hook-form";
import { useSelect } from "@refinedev/core";

const PostEdit: React.FC = () => {
const { formProps, saveButtonProps, query } = useForm<IPost>({
warnWhenUnsavedChanges: true,
});

const postData = query?.data?.data;
const { selectProps: categorySelectProps } = useSelect<ICategory>({
resource: "categories",
defaultValue: postData?.category?.id,
});
const { selectProps: brandSelectProps } = useSelect<IBrand>({
resource: "brands",
defaultValue: postData?.brand?.id,
});

const onFinish = (values: any) => {
// Filter out empty objects
if (!values.category?.id) {
values.category = null;
}
if (!values.brand?.id) {
values.brand = null;
}
// Submit the form with filtered values
formProps.onFinish(values);
};
return (
<Form {...formProps} layout="vertical" onFinish={onFinish}>
<Form.Item
label="Title"
name="title"
rules={[{ required: true }]}
>
<Input />
</Form.Item>
<Form.Item
label="Category"
name={["category", "id"]}
initialValue={null}
>
<Select {...categorySelectProps} />
</Form.Item>
<Form.Item
label="Brand"
name={["brand", "id"]}
initialValue={null}
>
<Select {...brandSelectProps} />
</Form.Item>
<Button type="primary" {...saveButtonProps}>
Save
</Button>
</Form>
);
};

export default PostEdit;
In this example, the initialValue for both category.id and brand.id is set to null. This ensures that if no value is provided, the fields will be set to null, which TypeORM can handle correctly. Additionally, the onFinish handler ensures that if the id is not provided, the fields are explicitly set to null before submitting the form data. For more information, you can refer to the refine documentation on forms and relationships (https://refine.dev/docs/guides-concepts/forms/#relationships-). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4mo ago
<@238969575289389057> kapa.ai is still learning and improving, please let us know how it did by reacting below