Skip to main content

4.4. Adding Create Page

This post shows how to implement the create page of blog_posts resource without resorting to <MuiCreateInferencer />. We replace the existing code inside the src/pages/blog-posts/create.tsx file with the Inferencer-generated refine and Material UI components.

The Create Page

The Inferencer-generated <BlogPostCreate /> component is available at the /blog-posts/create route. When we visit the page, we can view the code in a modal by clicking on Show the auto-generated code button. The generated component looks like this:

Show generated code

import { Create, useAutocomplete } from "@refinedev/mui";
import { Box, TextField, Autocomplete } from "@mui/material";
import { useForm } from "@refinedev/react-hook-form";
import { Controller } from "react-hook-form";

export const BlogPostCreate = () => {
const {
saveButtonProps,
refineCore: { formLoading },
register,
control,
formState: { errors },
} = useForm();

const { autocompleteProps: categoryAutocompleteProps } = useAutocomplete({
resource: "categories",
});

return (
<Create isLoading={formLoading} saveButtonProps={saveButtonProps}>
<Box
component="form"
sx={{ display: "flex", flexDirection: "column" }}
autoComplete="off"
>
<TextField
{...register("title", {
required: "This field is required",
})}
error={!!(errors as any)?.title}
helperText={(errors as any)?.title?.message}
margin="normal"
fullWidth
InputLabelProps={{ shrink: true }}
type="text"
label="Title"
name="title"
/>
<TextField
{...register("content", {
required: "This field is required",
})}
error={!!(errors as any)?.content}
helperText={(errors as any)?.content?.message}
margin="normal"
fullWidth
InputLabelProps={{ shrink: true }}
multiline
label="Content"
name="content"
/>
<Controller
control={control}
name="category"
rules={{ required: "This field is required" }}
// eslint-disable-next-line
defaultValue={null as any}
render={({ field }) => (
<Autocomplete
{...categoryAutocompleteProps}
{...field}
onChange={(_, value) => {
field.onChange(value);
}}
getOptionLabel={(item) => {
return (
categoryAutocompleteProps?.options?.find(
(p) =>
p?.id?.toString() ===
item?.id?.toString(),
)?.title ?? ""
);
}}
isOptionEqualToValue={(option, value) =>
value === undefined ||
option?.id?.toString() === value?.id?.toString()
}
renderInput={(params) => (
<TextField
{...params}
label="Category"
margin="normal"
variant="outlined"
error={!!(errors as any)?.category?.id}
helperText={
(errors as any)?.category?.id?.message
}
required
/>
)}
/>
)}
/>
<TextField
{...register("status", {
required: "This field is required",
})}
error={!!(errors as any)?.status}
helperText={(errors as any)?.status?.message}
margin="normal"
fullWidth
InputLabelProps={{ shrink: true }}
type="text"
label="Status"
name="status"
/>
{/*
DatePicker component is not included in "@refinedev/mui" package.
To use a <DatePicker> component, you can follow the official documentation for Material UI.

Docs: https://mui.com/x/react-date-pickers/date-picker/#basic-usage
*/}
<TextField
{...register("createdAt", {
required: "This field is required",
})}
error={!!(errors as any)?.createdAt}
helperText={(errors as any)?.createdAt?.message}
margin="normal"
fullWidth
InputLabelProps={{ shrink: true }}
label="Created At"
name="createdAt"
/>
</Box>
</Create>
);
};

Below, we briefly make sense of the components and hooks used in the above <BlogPostCreate/> component.

Understanding the Create Page Components

Refer to the Material UI documentation for more information

Handling Relationships

The blog_posts resource is associated with the categories resource. In the create blog post page, we have a category field which needs to be filled with select options fetched from the categories resource. In order to meet this requirement, we are using the useAutocomplete() hook provided by refine to prepopulate the category select options.

It is done like below:

const { selectProps: categorySelectProps } = useAutocomplete({
resource: "categories",
});

This hook fetches categories data by relaying its accepted arguments to the dataProvider's getList() method. Then, it exposes the props tailored for the <Autocomplete /> component to consume.

Refer to the useAutocomplete() documentation for more information

Refer to the Material UI <Autocomplete /> documentation for more information

Let's copy this code generated by Inferencer and paste it into the file at src/pages/blog-posts/create.tsx. We should replace the existing code that uses the <MuiCreateInferencer />.

Now, if we view the blog post create page in the browser at localhost:5173/blog-posts/create, we see the same forms being rendered, except the Show the auto-generated code is missing because we removed the <MuiCreateInferencer /> component:

localhost:5173/blog-posts/create

Checklist