0

I want to create a custom save button inside the TopToolbar component, but no matter how I approach the situation it just doesn't work, regardless of the usage of useSaveContext() save method explicitly on a Button element.

Can you point me to the right direction ?

here is a snippet:

import SyncIcon from '@mui/icons-material/Sync';
import { IconButton } from '@mui/material';
import {
  Button,
  Edit,
  ExportButton,
  RadioButtonGroupInput,
  SimpleForm,
  TextInput,
  TopToolbar,
  useEditContext,
  useEditController,
  useSaveContext,
} from 'react-admin';
import styles from './CustomerEdit.module.scss';

const TopSave = () => {
  const { record, save } = useEditController();
  console.log('record', record);
  const saveHandler = async () => {
    if (save) {
      await save(record);
    }
  };

  return <Button variant="outlined" label="Save" onClick={saveHandler} />;
};

const CustomerEditActions = () => (
  <TopToolbar>
    <ExportButton variant="text" />
    <TopSave />
    <IconButton aria-label="Sync data">
      <SyncIcon color="primary" />
    </IconButton>
  </TopToolbar>
);

function CustomerEdit() {
  return (
    <Edit
      sx={{
        '& .RaEdit-card': {
          border: 'none',
          display: 'flex',
          justifyContent: 'center',
        },
      }}
      actions={<CustomerEditActions />}
    >
      <SimpleForm>
        <div className={styles.formContainer}>
          <div className={styles.title}>
            <h2>Person</h2>
            <RadioButtonGroupInput
              source="contactSalutation"
              choices={[
                { id: 'HERR', name: 'Herr' },
                { id: 'FRAU', name: 'Frau' },
              ]}
            />
          </div>
          <div className={styles.contactsGrid}>
            <TextInput source="navisionId" label="Kundennummer" size="medium" />
            <TextInput source="contactFirstName" label="Vorname" size="medium" />
            <TextInput source="nameAddition" label="Namenzusatz" size="medium" />
            <TextInput source="contactLastName" label="Nachname" size="medium" />
            <TextInput source="companyName" label="Firmen Name" size="medium" />
          </div>
          <div className={styles.title}>
            <h2>Kontakt</h2>
          </div>
          <div className={styles.contactsGrid}>
            <TextInput source="contactTelephone" label="telefonnummer" size="medium" />
            <TextInput source="invoiceEmail" label="Rechnungs E-Mail" size="medium" />
            <TextInput source="street" label="Adresse" size="medium" />
            <TextInput source="addressAddition" label="Adressezusatz" size="medium" />
            <TextInput source="zip" label="PLZ" size="medium" />
            <TextInput source="city" label="Stadt" size="medium" />
          </div>
        </div>
      </SimpleForm>
    </Edit>
  );
}

export default CustomerEdit;

I tried implementing it as shown above.

3
  • what's wrong with what you have above? Is there an error when you click the button? Commented Jun 7 at 14:43
  • 2
    You can implement your button based on the SaveButton sources: github.com/marmelab/react-admin/blob/master/packages/…
    – MaxAlex
    Commented Jun 10 at 4:15
  • Thanks @MaxAlex it is a good idea, until it's not... Honestly, all I need is the SimpleForm state to be passed into the save method provided by the useSaveContext hook, then I'm done... I really hate when you literally have to reverse engineer 100's of lines of code for a stupid simple stuff like that.
    – Pathwalker
    Commented Jun 10 at 9:28

1 Answer 1

0

Apparently the most simple solution I found is this:

Just used css to move the toolbar from the bottom. SaveButton is the React-Admin built in component still.

const CustomerEditToolbar = () => (
  <TopToolbar sx={{ position: 'absolute', top: 100, right: 60, display: 'flex', alignItems: 'center' }}>
    <BackButton redirectTo="/debitors" />
    <ExportButton variant="text" />
    <SaveButton icon={<></>} />
    <IconButton aria-label="Sync data">
      <SyncIcon color="primary" />
    </IconButton>
  </TopToolbar>
);

function CustomerEdit() {
  const translate = useTranslate();
  return (
    <Edit
      sx={{
        '& .RaEdit-card': {
          border: 'none',
          display: 'flex',
          justifyContent: 'center',
        },
      }}
    >
      <SimpleForm toolbar={<CustomerEditToolbar />}>
        <div className={styles.formContainer}>
          <div className={styles.title}>
            <h2>{translate('resources.debitors.person')}</h2>
            <RadioButtonGroupInput
              source="contactSalutation"
              choices={[
                { id: 'HERR', name: translate('register.contact_salutation_male') },
                { id: 'FRAU', name: translate('register.contact_salutation_female') },
              ]}
            />
          </div>
          <div className={styles.contactsGrid}>
            <TextInput
              source="contactFirstName"
              label={translate('resources.debitors.fields.contactFirstName')}
              size="medium"
            />
            <TextInput
              source="nameAddition"
              label={translate('resources.debitors.fields.nameAddition')}
              size="medium"
            />
            <TextInput
              source="contactLastName"
              label={translate('resources.debitors.fields.contactLastName')}
              size="medium"
            />
            <TextInput
              source="companyName"
              label={translate('resources.debitors.fields.companyName')}
              size="medium"
              readOnly
            />
            <TextInput
              source="navisionId"
              label={translate('resources.debitors.fields.navisionId')}
              size="medium"
              readOnly
            />
          </div>
          <div className={styles.title}>
            <h2>{translate('resources.debitors.contact')}</h2>
          </div>
          <div className={styles.contactsGrid}>
            <TextInput
              source="contactTelephone"
              label={translate('resources.debitors.fields.telephone')}
              size="medium"
            />
            <TextInput
              source="invoiceEmail"
              label={translate('resources.debitors.fields.invoiceEmail')}
              size="medium"
            />
            <TextInput source="street" label={translate('resources.debitors.fields.invoiceEmail')} size="medium" />
            <TextInput
              source="addressAddition"
              label={translate('resources.debitors.fields.addressAddition')}
              size="medium"
            />
            <TextInput source="zip" label={translate('resources.debitors.fields.zip')} size="medium" />
            <TextInput source="city" label={translate('resources.debitors.fields.addressAddition')} size="medium" />
          </div>
        </div>
      </SimpleForm>
    </Edit>
  );
}

1
  • This is indeed the way to go. To access the form values (to save them), you need to be in a component that is a child of <Form>. SimpleForm's toolbar is inside the form so it works, whereas Edit's actions is outside of the form so it can't work.
    – slax57
    Commented Jun 12 at 9:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.