Skip to content

Commit

Permalink
Merge pull request #4132 from marmelab/extend-pagination
Browse files Browse the repository at this point in the history
Make pagination more extendable
  • Loading branch information
fzaninotto authored Dec 11, 2019
2 parents dd06be6 + e9937eb commit 7f9b7ce
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 73 deletions.
145 changes: 83 additions & 62 deletions docs/List.md
Original file line number Diff line number Diff line change
Expand Up @@ -573,68 +573,6 @@ export const PostList = (props) => (
const filterSentToDataProvider = { ...filterDefaultValues, ...filterChosenByUser, ...filters };
```

### Pagination

Here are all the props required by the <Pagination> component:

* `page`: The current page number (integer). First page is `1`.
* `perPage`: The number of records per page.
* `setPage`: `function(page: number) => void`. A function that set the current page number.
* `total`: The total number of records.

You don't need to fill these props when you pass the `Pagination` component to the `List` component through the `pagination` prop: `<List pagination={<Pagination />}>`.

You can also replace the default pagination element by your own. For instance, you can modify the default pagination by adjusting the "rows per page" selector.

```jsx
// in src/MyPagination.js
import { Pagination, List } from 'react-admin';

const PostPagination = props => <Pagination rowsPerPageOptions={[10, 25, 50, 100]} {...props} />;

export const PostList = (props) => (
<List {...props} pagination={<PostPagination />}>
...
</List>
);
```

**Tip**: Pass an empty array to `rowsPerPageOptions` to disable the rows per page selection.

Alternately, if you want to replace the default pagination by a "<previous - next>" pagination, create a pagination component like the following:

```jsx
import Button from '@material-ui/core/Button';
import ChevronLeft from '@material-ui/icons/ChevronLeft';
import ChevronRight from '@material-ui/icons/ChevronRight';
import Toolbar from '@material-ui/core/Toolbar';

const PostPagination = ({ page, perPage, total, setPage }) => {
const nbPages = Math.ceil(total / perPage) || 1;
return (
nbPages > 1 &&
<Toolbar>
{page > 1 &&
<Button color="primary" key="prev" icon={ChevronLeft} onClick={() => setPage(page - 1)}>
Prev
</Button>
}
{page !== nbPages &&
<Button color="primary" key="next" icon={ChevronRight} onClick={() => setPage(page + 1)} labelPosition="before">
Next
</Button>
}
</Toolbar>
);
}

export const PostList = (props) => (
<List {...props} pagination={<PostPagination />}>
...
</List>
);
```

### Aside component

You may want to display additional information on the side of the list. Use the `aside` prop for that, passing the component of your choice:
Expand Down Expand Up @@ -1388,3 +1326,86 @@ export const UserList = ({ permissions, ...props }) => {
{% endraw %}
**Tip**: Note how the `permissions` prop is passed down to the custom `filters` component.
## Pagination
Here are all the props required by the <Pagination> component:
* `page`: The current page number (integer). First page is `1`.
* `perPage`: The number of records per page.
* `setPage`: `function(page: number) => void`. A function that set the current page number.
* `total`: The total number of records.
* `actions`: A component that displays the pagination buttons (default: `PaginationActions`)
* `limit`: An element that is displayed if there is no data to show (default: `<PaginationLimit>`)

You don't need to fill these props when you pass the `Pagination` component to the `List` component through the `pagination` prop: `<List pagination={<Pagination />}>`.
You can also replace the default pagination element by your own. For instance, you can modify the default pagination by adjusting the "rows per page" selector.
```jsx
// in src/MyPagination.js
import { Pagination, List } from 'react-admin';

const PostPagination = props => <Pagination rowsPerPageOptions={[10, 25, 50, 100]} {...props} />;

export const PostList = (props) => (
<List {...props} pagination={<PostPagination />}>
...
</List>
);
```
**Tip**: Pass an empty array to `rowsPerPageOptions` to disable the rows per page selection.
Alternately, if you want to replace the default pagination by a "<previous - next>" pagination, create a pagination component like the following:
```jsx
import Button from '@material-ui/core/Button';
import ChevronLeft from '@material-ui/icons/ChevronLeft';
import ChevronRight from '@material-ui/icons/ChevronRight';
import Toolbar from '@material-ui/core/Toolbar';

const PostPagination = ({ page, perPage, total, setPage }) => {
const nbPages = Math.ceil(total / perPage) || 1;
return (
nbPages > 1 &&
<Toolbar>
{page > 1 &&
<Button color="primary" key="prev" icon={ChevronLeft} onClick={() => setPage(page - 1)}>
Prev
</Button>
}
{page !== nbPages &&
<Button color="primary" key="next" icon={ChevronRight} onClick={() => setPage(page + 1)} labelPosition="before">
Next
</Button>
}
</Toolbar>
);
}

export const PostList = (props) => (
<List {...props} pagination={<PostPagination />}>
...
</List>
);
```
But if you just want to change the color property of the pagination button, you can extend the existing components:
```jsx
import {
List,
Pagination as RaPagination,
PaginationActions as RaPaginationActions,
} from 'react-admin';

export const PaginationActions = props => <RaPaginationActions {...props} color="secondary" />;

export const Pagination = props => <RaPagination {...props} ActionsComponent={PaginationActions} />;

export const UserList = props => (
<List {...props} pagination={<Pagination />}>
</List>
);
```
16 changes: 12 additions & 4 deletions packages/ra-ui-materialui/src/list/Pagination.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import PropTypes from 'prop-types';
import { TablePagination, Toolbar, useMediaQuery } from '@material-ui/core';
import { useTranslate, sanitizeListRestProps } from 'ra-core';

import PaginationActions from './PaginationActions';
import PaginationLimit from './PaginationLimit';
import DefaultPaginationActions from './PaginationActions';
import DefaultPaginationLimit from './PaginationLimit';

const emptyArray = [];

Expand All @@ -16,6 +16,8 @@ const Pagination = ({
total,
setPage,
setPerPage,
actions,
limit,
...rest
}) => {
useEffect(() => {
Expand Down Expand Up @@ -64,8 +66,9 @@ const Pagination = ({
);

if (total === 0) {
return loading ? <Toolbar variant="dense" /> : <PaginationLimit />;
return loading ? <Toolbar variant="dense" /> : limit;
}

if (isSmall) {
return (
<TablePagination
Expand All @@ -80,14 +83,15 @@ const Pagination = ({
/>
);
}

return (
<TablePagination
count={total}
rowsPerPage={perPage}
page={page - 1}
onChangePage={handlePageChange}
onChangeRowsPerPage={handlePerPageChange}
ActionsComponent={PaginationActions}
ActionsComponent={actions}
component="span"
labelRowsPerPage={translate('ra.navigation.page_rows_per_page')}
labelDisplayedRows={labelDisplayedRows}
Expand All @@ -106,10 +110,14 @@ Pagination.propTypes = {
setPage: PropTypes.func,
setPerPage: PropTypes.func,
total: PropTypes.number,
actions: PropTypes.node,
limit: PropTypes.element,
};

Pagination.defaultProps = {
rowsPerPageOptions: [5, 10, 25],
actions: DefaultPaginationActions,
limit: <DefaultPaginationLimit />,
};

export default React.memo(Pagination);
27 changes: 20 additions & 7 deletions packages/ra-ui-materialui/src/list/PaginationActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ function PaginationActions({
rowsPerPage,
count,
onChangePage,
color,
size,
}) {
const classes = useStyles({ classes: classesOverride });
const translate = useTranslate();
Expand Down Expand Up @@ -102,12 +104,12 @@ function PaginationActions({
</span>
) : (
<Button
size={size}
className="page-number"
color={pageNum === page + 1 ? 'default' : 'primary'}
color={pageNum === page + 1 ? 'default' : color}
key={pageNum}
data-page={pageNum - 1}
onClick={gotoPage}
size="small"
>
{pageNum}
</Button>
Expand All @@ -116,16 +118,20 @@ function PaginationActions({
};

const nbPages = getNbPages();
if (nbPages === 1) return <div className={classes.actions} />;

if (nbPages === 1) {
return <div className={classes.actions} />;
}

return (
<div className={classes.actions}>
{page > 0 && (
<Button
color="primary"
color={color}
size={size}
key="prev"
onClick={prevPage}
className="previous-page"
size="small"
>
<ChevronLeft />
{translate('ra.navigation.prev')}
Expand All @@ -134,11 +140,11 @@ function PaginationActions({
{renderPageNums()}
{page !== nbPages - 1 && (
<Button
color="primary"
color={color}
size={size}
key="next"
onClick={nextPage}
className="next-page"
size="small"
>
{translate('ra.navigation.next')}
<ChevronRight />
Expand All @@ -162,6 +168,13 @@ PaginationActions.propTypes = {
onChangePage: PropTypes.func.isRequired,
page: PropTypes.number.isRequired,
rowsPerPage: PropTypes.number.isRequired,
color: PropTypes.oneOf(['primary', 'secondary']),
size: PropTypes.oneOf(['small', 'medium', 'large']),
};

PaginationActions.defaultProps = {
color: 'primary',
size: 'small',
};

export default React.memo(PaginationActions);

0 comments on commit 7f9b7ce

Please sign in to comment.