@@ -595,48 +709,55 @@ const PostList = props => (
);
```
+
{% endraw %}
The `aside` component receives the same props as the `List` child component, including the following:
-* `basePath`,
-* `currentSort`,
-* `data`,
-* `defaultTitle`,
-* `filterValues`,
-* `ids`,
-* `page`,
-* `perPage`,
-* `resource`,
-* `selectedIds`,
-* `total`,
-* `version`,
+- `basePath`,
+- `currentSort`,
+- `data`,
+- `defaultTitle`,
+- `filterValues`,
+- `ids`,
+- `page`,
+- `perPage`,
+- `resource`,
+- `selectedIds`,
+- `total`,
+- `version`,
That means you can display additional details of the current list in the aside component:
{% raw %}
+
```jsx
const Aside = ({ data, ids }) => (
Posts stats
- Total views: {ids.map(id => data[id]).reduce((sum, post) => sum + post.views, 0)}
+ Total views:{' '}
+ {ids.map(id => data[id]).reduce((sum, post) => sum + post.views, 0)}
);
```
+
{% endraw %}
-### Empty state
+### Empty page
+
+When there is no result, and there is no active filter, and the resource has a create page, react-admin displays a special page inviting the user to create the first record.
-When there is no result, and there is no active filter, and the resource has a create page then a special page inviting the user to create the first record is displayed. Use the `emptyState` prop to modify that page, passing your custom component:
+You can use the `empty` prop to replace that page by a custom component:
{% raw %}
+
```jsx
import Button from '@material-ui/core/Button';
import { CreateButton, List } from 'react-admin';
-const EmptyState = ({ basePath }) => (
+const Empty = ({ basePath, resource }) => (
No products available
Create one or import from a file
@@ -646,12 +767,26 @@ const EmptyState = ({ basePath }) => (
);
const ProductList = props => (
-
} {...props}>
+
} {...props}>
...
);
+```
-The `emptyState` component receives the same props as the `aside` prop. Read the [section above](#aside-component) to check them.
+The `empty` component receives the same props as the `List` child component, including the following:
+
+- `basePath`,
+- `currentSort`,
+- `data`,
+- `defaultTitle`,
+- `filterValues`,
+- `ids`,
+- `page`,
+- `perPage`,
+- `resource`,
+- `selectedIds`,
+- `total`,
+- `version`,
### Component
@@ -673,7 +808,7 @@ const PostList = props => (
...
);
-```
+````
The default value for the `component` prop is `Card`.
@@ -681,16 +816,17 @@ The default value for the `component` prop is `Card`.
The `List` component accepts the usual `className` prop but you can override many class names injected to the inner components by React-admin thanks to the `classes` property (as most Material UI components, see their [documentation about it](https://material-ui.com/customization/components/#overriding-styles-with-classes)). This property accepts the following keys:
-* `root`: alternative to using `className`. Applied to the root element.
-* `header`: applied to the page header
-* `actions`: applied to the actions container
-* `noResults`: applied to the component shown when there is no result
+- `root`: alternative to using `className`. Applied to the root element.
+- `header`: applied to the page header
+- `actions`: applied to the actions container
+- `noResults`: applied to the component shown when there is no result
Here is an example of how you can override some of these classes:
You can customize the list styles by passing a `classes` object as prop, through `useStyles()`. Here is an example:
{% raw %}
+
```jsx
import { makeStyles } from '@material-ui/core';
@@ -713,6 +849,7 @@ const PostList = props => {
export PostList;
```
+
{% endraw %}
## The `
` component
@@ -726,7 +863,9 @@ import { Admin, Resource, ListGuesser } from 'react-admin';
import jsonServerProvider from 'ra-data-json-server';
const App = () => (
-
+
);
@@ -746,11 +885,11 @@ The `Datagrid` component renders a list of records as a table. It is usually use
Here are all the props accepted by the component:
-* [`body`](#body-element)
-* [`rowStyle`](#row-style-function)
-* [`rowClick`](#rowclick)
-* [`expand`](#expand)
-* [`isRowSelectable`](#isrowselectable)
+- [`body`](#body-element)
+- [`rowStyle`](#row-style-function)
+- [`rowClick`](#rowclick)
+- [`expand`](#expand)
+- [`isRowSelectable`](#isrowselectable)
It renders as many columns as it receives `` children.
@@ -759,7 +898,7 @@ It renders as many columns as it receives `` children.
import React from 'react';
import { List, Datagrid, TextField, EditButton } from 'react-admin';
-export const PostList = (props) => (
+export const PostList = props => (
@@ -771,7 +910,7 @@ export const PostList = (props) => (
);
```
-The `Datagrid` is an *iterator* component: it receives an array of ids, and a data store, and is supposed to iterate over the ids to display each record. Another example of iterator component is [``](#the-singlefieldlist-component).
+The `Datagrid` is an _iterator_ component: it receives an array of ids, and a data store, and is supposed to iterate over the ids to display each record. Another example of iterator component is [``](#the-singlefieldlist-component).
### Body element
@@ -787,14 +926,21 @@ import TableCell from '@material-ui/core/TableCell';
import TableRow from '@material-ui/core/TableRow';
import Checkbox from '@material-ui/core/Checkbox';
-const MyDatagridRow = ({ record, resource, id, onToggleItem, children, selected, basePath }) => (
+const MyDatagridRow = ({
+ record,
+ resource,
+ id,
+ onToggleItem,
+ children,
+ selected,
+ basePath,
+}) => (
{/* first column: selection checkbox */}
- {record.selectable && onToggleItem(id)}
- />}
+ {record.selectable && (
+ onToggleItem(id)} />
+ )}
{/* data columns based on children */}
{React.Children.map(children, field => (
@@ -809,7 +955,9 @@ const MyDatagridRow = ({ record, resource, id, onToggleItem, children, selected,
);
-const MyDatagridBody = props => } />;
+const MyDatagridBody = props => (
+ } />
+);
const MyDatagrid = props => } />;
const PostList = props => (
@@ -819,7 +967,7 @@ const PostList = props => (
...
-)
+);
export default PostList;
```
@@ -834,11 +982,9 @@ For instance, this allows to apply a custom background to the entire row if one
const postRowStyle = (record, index) => ({
backgroundColor: record.nb_views >= 500 ? '#efe' : 'white',
});
-export const PostList = (props) => (
+export const PostList = props => (
-
- ...
-
+ ...
);
```
@@ -848,27 +994,26 @@ export const PostList = (props) => (
You can catch clicks on rows to redirect to the show or edit view by setting the `rowClick` prop:
```jsx
-export const PostList = (props) => (
+export const PostList = props => (
-
- ...
-
+ ...
);
```
`rowClick` accepts the following values:
-* "edit" to redirect to the edition vue
-* "show" to redirect to the show vue
-* "expand" to open the `expand` panel
-* "toggleSelection" to trigger the `onToggleItem` function
-* a function `(id, basePath, record) => path` to redirect to a custom path
+- "edit" to redirect to the edition vue
+- "show" to redirect to the show vue
+- "expand" to open the `expand` panel
+- "toggleSelection" to trigger the `onToggleItem` function
+- a function `(id, basePath, record) => path` to redirect to a custom path
**Tip**: If you pass a function, it can return `edit`, `show` or a router path. This allows to redirect to either `edit` or `show` after checking a condition on the record. For example:
```js
-const postRowClick = (id, basePath, record) => record.editable ? 'edit' : 'show';
+const postRowClick = (id, basePath, record) =>
+ record.editable ? 'edit' : 'show';
```
**Tip**: If you pass a function, it can also return a promise allowing you to check an external API before returning a path. For example:
@@ -876,7 +1021,8 @@ const postRowClick = (id, basePath, record) => record.editable ? 'edit' : 'show'
```js
import fetchUserRights from './fetchUserRights';
-const postRowClick = (id, basePath, record) => fetchUserRights().then(({ canEdit }) => canEdit ? 'edit' : 'show');
+const postRowClick = (id, basePath, record) =>
+ fetchUserRights().then(({ canEdit }) => (canEdit ? 'edit' : 'show'));
```
### `expand`
@@ -884,6 +1030,7 @@ const postRowClick = (id, basePath, record) => fetchUserRights().then(({ canEdit
To show more data from the resource without adding too many columns, you can show data in an expandable panel below the row on demand, using the `expand` prop. For instance, this code shows the `body` of a post in an expandable panel:
{% raw %}
+
```jsx
const PostPanel = ({ id, record, resource }) => (
@@ -899,22 +1046,21 @@ const PostList = props => (
-)
+);
```
### `isRowSelectable`
-You can customize which rows will show a selection checkbox using the `isRowSelectable` prop. It expects a function that will receive the record of each `` and returns a boolean expression. For instance, this code shows a checkbox only for rows with an id greater than 300:
+You can customize which rows will show a selection checkbox using the `isRowSelectable` prop. It expects a function that will receive the record of each `` and returns a boolean expression. For instance, this code shows a checkbox only for rows with an id greater than 300:
```jsx
export const PostList = props => (
- record.id > 300 }>
- ...
-
+ record.id > 300}>...
);
```
+
{% endraw %}
![expandable panel](./img/datagrid_expand.gif)
@@ -946,7 +1092,7 @@ const PostList = props => (
-)
+);
```
The result will be the same as in the previous snippet, except that `` encloses the content inside a material-ui ``.
@@ -979,26 +1125,27 @@ const PostList = props => (
-)
+);
```
### CSS API
The `Datagrid` component accepts the usual `className` prop but you can override many class names injected to the inner components by React-admin thanks to the `classes` property (as most Material UI components, see their [documentation about it](https://material-ui.com/customization/components/#overriding-styles-with-classes)). This property accepts the following keys:
-* `table`: alternative to using `className`. Applied to the root element.
-* `tbody`: applied to the tbody
-* `headerCell`: applied to each header cell
-* `row`: applied to each row
-* `rowEven`: applied to each even row
-* `rowOdd`: applied to each odd row
-* `rowCell`: applied to each row cell
+- `table`: alternative to using `className`. Applied to the root element.
+- `tbody`: applied to the tbody
+- `headerCell`: applied to each header cell
+- `row`: applied to each row
+- `rowEven`: applied to each even row
+- `rowOdd`: applied to each odd row
+- `rowCell`: applied to each row cell
Here is an example of how you can override some of these classes:
You can customize the `` styles by passing a `classes` object as prop, through `useStyles()`. Here is an example:
{% raw %}
+
```jsx
import React from 'react';
import { makeStyles } from '@material-ui/core';
@@ -1022,6 +1169,7 @@ const PostList = props => {
export PostList;
```
+
{% endraw %}
**Tip**: If you want to override the `header` and `cell` styles independently for each column, use the `headerClassName` and `cellClassName` props in `` components. For instance, to hide a certain column on small screens:
@@ -1137,12 +1285,14 @@ For mobile devices, a `` is often unusable - there is simply not enoug
import React from 'react';
import { List, SimpleList } from 'react-admin';
-export const PostList = (props) => (
+export const PostList = props => (
record.title}
secondaryText={record => `${record.views} views`}
- tertiaryText={record => new Date(record.published_at).toLocaleDateString()}
+ tertiaryText={record =>
+ new Date(record.published_at).toLocaleDateString()
+ }
/>
);
@@ -1156,9 +1306,16 @@ export const PostList = (props) => (
// in src/posts.js
import React from 'react';
import { useMediaQuery } from '@material-ui/core';
-import { List, SimpleList, Datagrid, TextField, ReferenceField, EditButton } from 'react-admin';
+import {
+ List,
+ SimpleList,
+ Datagrid,
+ TextField,
+ ReferenceField,
+ EditButton,
+} from 'react-admin';
-export const PostList = (props) => {
+export const PostList = props => {
const isSmall = useMediaQuery(theme => theme.breakpoints.down('sm'));
return (
@@ -1166,16 +1323,16 @@ export const PostList = (props) => {
record.title}
secondaryText={record => `${record.views} views`}
- tertiaryText={record => new Date(record.published_at).toLocaleDateString()}
+ tertiaryText={record =>
+ new Date(record.published_at).toLocaleDateString()
+ }
/>
) : (
-
- ...
-
+ ...
)}
);
-}
+};
```
**Tip**: The `` items link to the edition page by default. You can set the `linkType` prop to `show` to link to the `` page instead.
@@ -1185,12 +1342,14 @@ export const PostList = (props) => {
import React from 'react';
import { List, SimpleList } from 'react-admin';
-export const PostList = (props) => (
+export const PostList = props => (
record.title}
secondaryText={record => `${record.views} views`}
- tertiaryText={record => new Date(record.published_at).toLocaleDateString()}
+ tertiaryText={record =>
+ new Date(record.published_at).toLocaleDateString()
+ }
linkType="show"
/>
@@ -1205,11 +1364,7 @@ When you want to display only one property of a list of records, instead of usin
```jsx
// Display all the tags for the current post
-
+
@@ -1222,11 +1377,7 @@ When you want to display only one property of a list of records, instead of usin
```jsx
// Display all the tags for the current post
-
+
@@ -1237,8 +1388,8 @@ When you want to display only one property of a list of records, instead of usin
A `` can delegate to any iterator component - `` is just one example. An iterator component must accept at least two props:
-- `ids` is an array of the ids currently displayed in the list
-- `data` is an object of all the fetched data for this resource, indexed by id.
+- `ids` is an array of the ids currently displayed in the list
+- `data` is an object of all the fetched data for this resource, indexed by id.
For instance, what if you prefer to show a list of cards rather than a datagrid?
@@ -1247,6 +1398,7 @@ For instance, what if you prefer to show a list of cards rather than a datagrid?
You'll need to create your own iterator component as follows:
{% raw %}
+
```jsx
// in src/comments.js
import React from 'react';
@@ -1256,38 +1408,57 @@ import CardContent from '@material-ui/core/CardContent';
import CardHeader from '@material-ui/core/CardHeader';
import Avatar from '@material-ui/core/Avatar';
import PersonIcon from '@material-ui/core/Avatar';
-import { List, TextField, DateField, ReferenceField, EditButton } from "react-admin";
+import {
+ List,
+ TextField,
+ DateField,
+ ReferenceField,
+ EditButton,
+} from 'react-admin';
const cardStyle = {
width: 300,
minHeight: 300,
margin: '0.5em',
display: 'inline-block',
- verticalAlign: 'top'
+ verticalAlign: 'top',
};
const CommentGrid = ({ ids, data, basePath }) => (
- {ids.map(id =>
-
- }
- subheader={}
- avatar={} />}
- />
-
-
-
-
- about
-
-
-
-
-
-
-
-
- )}
+ {ids.map(id => (
+
+ }
+ subheader={
+
+ }
+ avatar={} />}
+ />
+
+
+
+
+ about
+
+
+
+
+
+
+
+
+ ))}
);
CommentGrid.defaultProps = {
@@ -1295,12 +1466,13 @@ CommentGrid.defaultProps = {
ids: [],
};
-export const CommentList = (props) => (
+export const CommentList = props => (
);
```
+
{% endraw %}
As you can see, nothing prevents you from using `` components inside your own components... provided you inject the current `record`. Also, notice that components building links require the `basePath` component, which is also injected.
@@ -1312,6 +1484,7 @@ You might want to display some fields or filters only to users with specific per
Before rendering the `List`, react-admin calls the `authProvider.getPermissions()` method, and passes the result to the component as the `permissions` prop. It's up to your `authProvider` to return whatever you need to check roles and permissions inside your component.
{% raw %}
+
```jsx
const UserFilter = ({ permissions, ...props }) =>
@@ -1351,6 +1524,7 @@ export const UserList = ({ permissions, ...props }) => {
)
}
```
+
{% endraw %}
**Tip**: Note how the `permissions` prop is passed down to the custom `filters` component.