Search code examples
admin-on-restreact-admin

Only allow creation of new ArrayInput elements in edit/create & make existing ones immutable/display only


I have been reading the docs and forum for a day and haven't found a solution to my answer. I am wondering if the following is possible with react-admin.

I have a resource documents that for which templates can be created added. The number of templates is infinite, but once a template has been added, it shouldn't be editable or removable.

When I edit a document, I can edit it's title and description or add new templates, but I can't modify/delete the old ones.

Look at this image below for example:

Screenshot

Below Title, Description and Created on Date there is an ArrayInput field with the source='templates'.

The first entry corresponds to the one I already created, however its mutable. At the bottom is a simple datagrid that shows the templates.

I either need to have a datagrid and be able to only create new templates, or have the existing entries in the ArrayInput be immutable.

Is there a clean or hacky way to achieve this? If not, it should be a feature imo. What do you think?


Solution

  • This is a very specific usecase so we won't support this feature out of the box. However, as explained in the documentation, the only child accepted by the ArrayInput is an implementation of an iterator which is the component responsible for allowing add/remove and displaying the inputs. We only provide the SimpleFormIterator but you can make your own based on its source.

    I think you'll probably need an iterator component accepting two render props, one for the existing items which will return fields, and another one for the new items which will return inputs. It would be used like this:

    <ArrayInput source="templates">
        <SimpleFormIterator
            renderExisting={() => ([
                <TextField source="country" />,
                <TextField source="templateId" />,
                <NumberField source="pages" />,
            ])}
            renderNew={() => ([
                <TextInput source="country" />,
                <TextInput source="templateId" />,
                <NumberInput source="pages" />,
            ])}
        />
    </ArrayInput>