ReferenceManyInput in react-admin - reactjs

In react-admin we have ReferenceManyField. It would be fantastic to have also a component called ReferenceManyInput, with a functionallity very similar to the ArrayInput component (add, remove buttons) but with reference to a resource.
¿Does any one know if they have intention to include it or is there any workaround to achieve this?
The use case is:
I have a form for creating/editing an entity where one of its properties is an array of other related entities. I would like to add and/or remove new elements to that array and when submitting the main entity, it creates/updates/remove the related entity and the main entity.
Maybe I am asking for too much...
Thanks in advance

You're in luck: <ReferenceManyInput> was just published as part of React-admin Enterprise Edition. It works just like ReferenceManyField:
import {
Edit,
SimpleForm,
TextInput,
NumberInput,
ReferenceInput,
SelectInput,
} from 'react-admin';
import { ReferenceManyInput } from '#react-admin/ra-relationships';
const ProductEdit = () => (
<Edit mutationMode="optimistic">
<SimpleForm>
<TextInput source="name" />
<NumberInput source="price" />
<ReferenceInput source="category_id" reference="categories" />
<ReferenceManyInput reference="variants" target="product_id">
<SimpleFormIterator inline>
<TextInput source="sku" />
<SelectInput source="size" choices={sizes} />
<SelectInput source="color" choices={colors} />
<NumberInput source="stock" defaultValue={0} />
</SimpleFormIterator>
</ReferenceManyInput>
</SimpleForm>
</Edit>
);
The result looks like:
Check https://marmelab.com/ra-enterprise/modules/ra-relationships#referencemanyinput for details.

Related

React-admin: ReferenceInput doesn't show loading <LinearProgress> while loading possible options

I have simple react-admin edit form with ReferenceInput. The problem is that ReferenceInput never show progress bar, so it might be confusing for users to see no options while it's loading.
I manually set delay 2 seconds on API calls but ReferenceInput never show loading state.
import React from 'react';
import { ReferenceInput, ReferenceArrayInput, required, SelectArrayInput, SelectInput, SimpleForm, TextInput } from 'react-admin';
const ModelForm = props => (
<SimpleForm {...props}>
<TextInput source="name" validate={[required()]} />
<ReferenceInput reference="goods_types" source="goodsType" validate={[required()]}>
<SelectInput optionText="name" />
</ReferenceInput>
<ReferenceInput reference="manufacturers" source="manufacturer" validate={[required()]}>
<SelectInput optionText="name" />
</ReferenceInput>
<ReferenceArrayInput reference="manufacturers" source="manufacturer" format={v => [v]} validate={[required()]}>
<SelectArrayInput optionText="name" />
</ReferenceArrayInput>
</SimpleForm>
);
export default ModelForm;
Just for test I added ReferenceArrayInput component and it does show loading progress bar.
Is it bug in react-admin? Or am I missing something?
React-admin: 3.11.1
React Admin introduced a timeout with default value of 1000. The loading component only appear after this time. You can override this value by passing a prop to the component.
ref: https://github.com/marmelab/react-admin/blob/ea1f85c73f5be8f12544a0fccf32e4f6bd7452be/packages/ra-ui-materialui/src/layout/LinearProgress.tsx

React Admin - overiding handleSubmit on SimpleForm

What I want to achieve is this but using react admin SimpleForm instead of Form:
import React, { useState } from "react";
export function NameForm(props) {
const [name, setName] = useState("");
const handleSubmit = (evt) => {
evt.preventDefault();
alert(`Submitting Name ${name}`)
}
return (
<form onSubmit={handleSubmit}>
<label>
Frirst Name:
<input
type="text"
value={name}
onChange={e => setName(e.target.value)}
/>
</label>
<input type="submit" value="Submit" />
</form>
);
}
When I try the same pattern, i.e.:
<SimpleForm onSubmit={handleSubmit}>
it never reaches the handleSubmit function. I also tried:
<SimpleForm handleSubmit={handleSubmit}>
But again no joy.
The react admin docs here say:
Finally, it receives a handleSubmit function as prop, to be called with the updated record as an argument when the user submits the form.
Unfortunately being new to react this doesn't give me any clue as to what I should do to get this to work.
When you're using any third party library you need to follow their rules. Here you're using React admin library which support normal admin features like add/edit/listing etc. With minimal effort you can create admin panel.
So when you're focusing on creating form using React Admin , you can create add/edit form.
In your App.js you need to first define routing using Resource which contains create and edit attribute. In create/edit you can import your add/edit component and pass it. The example is given below. You can see dataProvider link is also provided. When you'll create edit form it will take data from there
// in src/App.js
import * as React from "react";
import { Admin, Resource } from 'react-admin';
import jsonServerProvider from 'ra-data-json-server';
import { PostCreate, PostEdit } from './posts';
const App = () => (
<Admin dataProvider={jsonServerProvider('https://jsonplaceholder.typicode.com')}>
<Resource name="posts" create={PostCreate} edit={PostEdit} />
</Admin>
);
export default App;
After creating proper routing you can go to your component and can create add/edit form just like below
// in src/posts.js
import * as React from "react";
import { Create, Edit, SimpleForm, TextInput, DateInput, ReferenceManyField, Datagrid, TextField, DateField, EditButton } from 'react-admin';
import RichTextInput from 'ra-input-rich-text';
export const PostCreate = (props) => (
<Create {...props}>
<SimpleForm>
<TextInput source="title" />
<TextInput source="teaser" options={{ multiLine: true }} />
<RichTextInput source="body" />
<DateInput label="Publication date" source="published_at" defaultValue={new Date()} />
</SimpleForm>
</Create>
);
export const PostEdit = (props) => (
<Edit {...props}>
<SimpleForm>
<TextInput disabled label="Id" source="id" />
<TextInput source="title" validate={required()} />
<TextInput multiline source="teaser" validate={required()} />
<RichTextInput source="body" validate={required()} />
<DateInput label="Publication date" source="published_at" />
<ReferenceManyField label="Comments" reference="comments" target="post_id">
<Datagrid>
<TextField source="body" />
<DateField source="created_at" />
<EditButton />
</Datagrid>
</ReferenceManyField>
</SimpleForm>
</Edit>
);
React-admin injects a few props to the create and edit views: the resource name, the basePath (the root URL), the permissions, and, in the case of the edit view, the record id. That’s why you need to pass the props to the <Create> and <Edit> components.
The <Create> and <Edit> components call the dataProvider, prepare the form submit handler, and render the page title and actions.
<SimpleForm> Which you mentioned in your question is responsible for creating the form only, it's not responsible for handleSubmit operation , <Create> and <Edit> components handle that.
To know more in details follow the React Admin <Create> and <Edit> doc carefully.
So I found the solution I was looking for thanks to the answer from Saswata Pal. To achieve the effect I was looking for I changed the component so it was like this:
<Create transform={transform}>
This allowed me to grab the form result before submission and modify.
Relevant docs here:
https://marmelab.com/blog/2020/06/09/react-admin-3-6.html

Is it possible to disable default sorting in React Admin?

I have simple question
Is it possible to disable default sorting by column id? Or at least change it globally?
Thanks for answer
EDIT:
To be more specific, I have REST API (OData) which returns "Id" instead of "id" so I have to set sort everytime I use related component to prevent undefined errors.
I would welcome option to disable default sort in related components.
If you are looking for a solution to disable sort option for that column, you can use sortable={false}.
Example usage:
import React from 'react';
import { List, Datagrid, TextField } from 'react-admin';
export const PostList = (props) => (
<List {...props}>
<Datagrid>
<TextField source="id" sortable={false} />
<TextField source="title" />
<TextField source="body" />
</Datagrid>
</List>
);
Or you can specify a default sort for the List.
export const PostList = (props) => (
<List {...props} sort={{ field: 'published_at', order: 'DESC' }}>
...
</List>
);

Access current record in admin on rest edit

I need to access the current record in admin on rest Edit. I have an entity and need one of it's properties to do a conditional task. I searched all over the internet and found nothing.
export const UserEdit = (props) => (
<Edit {...props}>
<SimpleForm>
<TextField source="Username" label="Username" />
</SimpleForm>
</Edit>
);
This is not possible with admin-on-rest but this is where React comes to the rescue, you can create a component to add this behaviour.
Something like:
const WithProps = ({children,...props}) => children(props);
And use it like this:
export const UserEdit = (props) => (
<Edit {...props}>
<WithProps>{({record,...props})=>
<SimpleForm record={record} {...props}>
<TextField source="Username" label="Username" />
</SimpleForm>}
</WithProps>
</Edit>
);
Are you looking for aor-dependent-input?
https://github.com/marmelab/aor-dependent-input
It allows to display an input depending on other inputs values. It's authored and supported by the admin-on-rest core team.
Normally you don't have an access to a record inside a SimpleForm.
Perhaps, you can define a custom field and wrap a TextField inside it with access to the record so as to perform a conditional check as desired.
ex:
const CustomTextField = ({record = {}, source}) => (
{ record.foo ? <TextField source="username" label="username" /> : <WhateverField /> }
);
and then, use the CustomTextField in your UserEdit instead.

admin-on-rest: customizing Edit component

I need to customize Edit component in two ways:
Add custom button, but not to the upper panel (with 'List' and
'Refresh' buttons), but at the bottom of the component (next to the default 'Save'
button).
Turn off redirect on default 'Save' button click (to make it just
save and stay on page).
How do I achieve this?
I came accross this unanswered question. Since I just did something like this very recently myself I will share how I did it here. I am using admin on rest 1.4.0 btw.
So, on your <Edit> component, add this toolbar={<MyCustomToolbar />}. Then create a custom toolbar with your buttons in it. On the button you can use redirect to redirect to another page.
Code example:
import { SaveButton, Toolbar, TextInput, Edit, SimpleForm } from 'admin-on-rest';
const MyToolbar = props =>
<Toolbar {...props} >
<SaveButton label="Save & to dashboard" redirect="/" />
.. more buttons here..
</Toolbar>;
export const EditForm = (props) => (
<Edit title="Edit" {...props}>
<SimpleForm toolbar={<MyToolbar />}>
<TextInput source="company_website" type="url" />
<TextInput source="address_street" />
<TextInput source="address_zip" />
<TextInput source="address_unitnr" />
<TextInput source="address_city" />
</SimpleForm>
</Edit>
);
Hope this helps!

Resources