Summary
I want to add a quick action button on a record show view that will display a dialog with a form field.
When the form is submitted, I want the data provided to dispatch an update action with the form field data plus a few option.
I know how to create action button that will dispatch update action on data provider, but I am stuck about how to handle a form on a dialog.
Tries (and failures)
So I started by creating a button displaying a dialog with a TextInput (from react-admin) on it:
const ValidateButton: FC<ButtonProps> = ({ record }) => {
const [open, setOpen] = useState<boolean>(false);
const handleInit = () => {
setOpen(true)
}
const handleCancel = () => {
setOpen(false);
}
const handleSubmit = () => {
setOpen(false);
}
return (
<>
<Button
label="Validate"
onClick={handleInit}
>
<ValidateIcon />
</Button>
<Dialog
open={open}
>
<DialogTitle>Validate</DialogTitle>
<DialogContent>
<TextInput
source="comment"
label="Validation comment"
/>
</DialogContent>
<DialogActions>
<Button
label="Cancel"
onClick={handleCancel}
/>
<Button
label="Validate"
onClick={handleSubmit}
/>
</DialogActions>
</Dialog>
</>
);
}
This gave me the following error:
Error: useField must be used inside of a <Form> component
Well. Pretty clear. So I tried wrapping it on a SimpleForm component:
<DialogContent>
<SimpleForm
form={createForm({ onSubmit: handleSubmit })}
resource="rides"
record={record}
>
<TextInput
source="comment"
label="Validation comment"
/>
</SimpleForm>
</DialogContent>
Then I got:
TypeError: can't access property "save", context is undefined
useSaveContext
node_modules/ra-core/esm/controller/details/SaveContext.js:23
20 | */
21 | export var useSaveContext = function (props) {
22 | var context = useContext(SaveContext);
> 23 | if (!context.save || !context.setOnFailure) {
24 | /**
25 | * The element isn't inside a <SaveContextProvider>
26 | * To avoid breakage in that case, fallback to props
The ValidateButton is implemented on the Show view toolbar:
const RideShowActions: FC<ShowActionsProps> = ({ basePath, data }) => {
if (!data) {
return null;
}
return (
<TopToolbar>
<ValidateButton />
{[
'created',
'validated',
'confirmed',
].includes(data?.status) && <CancelButton basePath={basePath} record={data} />}
<EditButton basePath={basePath} record={data} />
</TopToolbar>
);
};
export const RideShow: FC<ShowProps> = (props) => (
<Show
title={<RideTitle />}
actions={<RideShowActions />}
{...props}
>
<SimpleShowLayout>
// Show classic stuff.
</SimpleShowLayout>
</Show>
);
Question
I suppose the last error is because the SimpleForm needs to be placed on <Edit> or similar.
My goal is just to have an input with the same functionnality and UX/UI design than the edit form on a dialog and do custom actions.
What I am missing? How can I achieve that?
Note: I tried to directly use the TextField component of @material-ui/core. It works, but I loose all the react-admin functionnalities that will be useful to me like for ReferenceInput.