@vlsergey/react-bootstrap-pagetable
Ready-to-use-in-SPA table component
Goal of this component is provide standard and simple-to-use component to display and operate over data presented in tables. Such data are usually provided by server side using some find...
methods with page
and size
arguments, as well as filtering, sorting and other options.
Online demo: HERE
Main features:
Additional small features that nice to have:
API
Installation:
npm install --save @vlsergey/react-bootstrap-pagetable
Main component is exposed as default module export of library.
There are 2 main properties to define. First is itemModel
-- defines the data
structure, how to display data. Second is fetch
-- provides implementation
of method to query data from server (or memory).
import PageTable from '@vlsergey/react-bootstrap-pagetable';
return <PageTable
fetch={this.fetchDataImpl}
itemModel={itemModel} />
To enable react-router integration import another variant of PageTable
:
import {UncontrolledWithReactRouter as PageTable} from '@vlsergey/react-bootstrap-pagetable';
Property | Data type | Default value | Description |
---|
fetch | ( fetchArgs: FetchArgs ) => Promise<Page<T>> | required | See below |
itemModel | ItemModel<T> | required | See below |
actions | Action[] | 0 | Allows to display buttons at the bottom of page table and use them to execute actions over single or multiple elements from single page of the table. |
defaultPage | number | 0 | Default page to display (0-based) |
defaultSize | number | 10 | Default page size to display |
defaultSort | string | | Default page sort. One can specify only field name like name or field name and direction like name,ASC / name,DESC . |
footerElements | (() => JSX.Element)[][][] | | Elements to be rendered by DefaultFooter before page at the left (0), center (1), and right side (2). By default it's actions toolbar on the first line, visible fields settings button and page index at the left and page size at the right of the second line. |
footerRenderer | ( props: HeaderFooterPropsType ) | DefaultFooter | Component (function) used to render table footer with pagination and page size selector |
headerElements | (() => JSX.Element)[][][] | | Elements to be rendered by DefaultHeader before page at the left (0), center (1), and right side (2). By default it's visible fields settings button and page index at the left and page size at the right. |
headerRenderer | ( props: HeaderFooterPropsType ) | DefaultHeader | Component (function) used to render table header with pagination and page size selector |
itemFieldCellHyperlink | (item: T, field: FieldModel<T, unknown>) => string | () => null | Allow to wrap cell content in hyperlink element (<a> ). Will not be used when pageTable has at least single selected element. |
itemFieldCellLinkWrapper | (props: ItemFieldCellLinkWrapperProps<T, unknown>) => JSX.Element | DefaultItemFieldCellLinkWrapper by default. ReactRouterItemFieldCellLinkWrapper when react-router integration enabled | Implement hyperlink wrapper. By default it's usual <a> element (with appropriate styling to fill whole cell). Replaced with react-router-dom <Link> element when integration is enabled and provided hyperlink value is relative. |
itemFieldCellRenderer | ( props: ItemFieldCellRendererProps ) => JSX.Element | DefaultItemFieldCellRenderer | Allows to override default item cell renderer (including selection checkbox cell). |
onSelectedIdsChange | `(string[]) => unknown | undefined | Selection change listener (ids) |
onSelectedItemsChange | `((T | undefined)[]) => unknown | undefined |
noContentRow | ( tableColumnsCount: number ) => ReactNode | "no content on this page, select another page to display" | What to display instead of row when no data present on the fetched page |
rowsRenderer | ( props: RowsRendererProps ) => JSX.Element | DefaultRowsRenderer | Allows to override default rows renderer. |
rowProps | ( item: T ) => React.ComponentProps<'tr'> | () => ({}) | Additional properties for inner <tr> element |
size | undefined | 'lg' | 'sm' | undefined | Will be passed to react bootstrap Table component as well as to Button , Form.Control and other inner components to change their visible size. |
tableProps | props of react bootstrap <Table> component | {} | Additional properties for inner <Table> component |
urlParamsPrefix | string | "" | What is the prefix of page , size , sort and other URL arguments that PageTable should interact with. Only with react-router integration enabled. |
Item model
So far itemModel (itemModel: ItemModel
) defines 2 properties:
idF
(idF: (item: T) => string
). Defines a way to get unique
identifier of object in the data list. It's usually object ID. Identifier
should be unique in single data page scope and shall be unique in whole
table scope. Internally it's used to store selected rows identifiers and to
provide key
to React element array items.fields (fields: FieldModel<ItemModel, FieldValueType>[])
.
List of object properties that can be displayed in the table. Some of them are visible by default, some of them are hidden. Use can change this (along with order of fields). Each field model should have following properties:
key
(key: string
). Defines internal string key for field. Internally
it's used to provide key
to React element array items. In future versions
it will also be used to store 'shown/hidden' lists of column. Assumed to be
safe to change from version to version (nothing really bad happens on change).title
(title: string
). Field title text. Shown in table column header
cell. Title is string due to DOM limitations related to <option>
tag
behavior (for example it's used in visible fields list dialog).description
(description?: ReactNode
): Description of field. Optional.
Currently unused.sortable
(boolean
): is field sortable or not. Optional. Default false
. Enabling this will render additional sorting icons in table header cell and will allow user to change sorting by clicking on header cell. Component does not define a way to sort elements, only fills sort
field in FetchArgs
structure passed to fetch()
function.getter
(getter?: ( item: I, fieldModel: FieldModel<I, V>, itemModel: ItemModel<I> ) => V
).
Optional. Defines the way to obtain field value from object structure. By
default obtains object property using key
, i.e. item[fieldModel.key]
.render
(render: ( props: { value: V, item: I, itemModel: ItemModel<I> } ) => ReactNode
). Optional.
Defines the way to render object field as table cell content. By default
just outputs string and number values as ReactNode
, objects are stringified
using JSON.stringify()
, null
and undefined
are returned as null
.
Feel free to use function, React functional component or React class component
here. Props type is exported from library as ValueRendererProps
interface.headerCellContent
(props: ( field: FieldModel<ItemModel, FieldValueType> ) => JSX.Element
).
Optional. Allow to change default header cell react element (<th>
) content.
By default cell title is renderer with additional icons if field is sortable.valueCellProps
(valueCellProps?: ( value: V, item: unknown, fieldModel: FieldModel<V> ) => Record<string, unknown>
).
Optional. Provides additional value cell react element (<td>
) properties.
Example
Data example:
[
{ "id": "1", "name": "Alice", "birthday": "2001-02-03" },
{ "id": "2", "name": "Bob", "birthday": "2002-03-04" },
{ "id": "3", "name": "Carl", "birthday": "2003-04-05" }
]
Possible item model:
const itemModel = {
idF: ( { id } ) => id,
fields: [
{ key: 'name', title: 'Name', sortable: true },
{
key: 'birthday',
title: 'Birth Date',
render: ( { value } ) => new Date( Date.parse( value ) ).toLocaleDateString(),
sortable: true,
},
{
key: 'birthyear',
title: 'Birth Year',
getter: ( { birthday } ) => new Date( Date.parse( birthday ) ).getFullYear(),
sortable: true,
},
]
}
fetch()
fetch: ( fetchArgs: FetchArgs, fetchOptions: FetchOptions, fetchReason: FetchReason ) => Promise<Page<T>>
interface FetchArgs {
page: number,
size: number,
filter?: Record<string, unknown>;
sort?: { field: string, direction?: 'ASC' | 'DESC' }[]
}
interface FetchOptions {
signal?: AbortSignal,
}
export enum FetchReason {
FIRST_TIME_FETCH,
FETCH_ARGS_CHANGE,
REFRESH_REQUIRED,
}
interface Page<T> {
content: T[];
number: number;
totalElements: number;
totalPages: number;
}
Provides a way to get items to display. User shall not think about bouncing/scheduling/etc,
just provide data fetch implementation. page
field is 0-based.
Header and footer customization
First of all there are headerRenderer
and footerRenderer
props of PageTable
that allow to override header and footer rendering completely. Default implementation uses ControlledContext (and yours can too) to get access to controllable component props (such as current page and others).
Additionally there is headerElements
and footerElements
props that allows to pass array of elements to be drawn in header and footer. This is array of lines, line is array of columns, column is array of component classes (functions) that shall be rendered in header and footer. Default values are:
- For header:
[ [ [ VisibleFieldsButton, PageIndexSelector ], [ PageSizeSelector ] ] ]
- For footer:
[ [ [ VisibleFieldsButton, PageIndexSelector ], [ PageSizeSelector ] ], [ [ ActionsToolbar ] ] ]
Parts of header and footer are exported as:
DefaultFooter
and DefaultHeader
-- default implementation of header and footerActionsToolbar
-- action buttons toolbar (button toolbar)PageIndexSelector
-- pagination controlPageSizeSelector
-- page size select controlVisibleFieldsButton
-- button to show visible fields dialog
Utility functions
fetchFromArray
Emulates fetching data from provided array. Supports pagination and sorting (with strings and numbers).
import { fetchFromArray } from '@vlsergey/react-bootstrap-pagetable';
async function fetchFromArray<T>(
itemModel: ItemModel<T>,
src: T[],
fetchArgs: FetchArgs ): Promise<Page<T>>
fetchFromSpringDataRest
import { fetchFromSpringDataRest } from '@vlsergey/react-bootstrap-pagetable';
async function fetchFromSpringDataRest<K extends string, T>(
url: string,
fetchArgs: FetchArgs,
responseCollectionKey: K ): Promise<Page<T>>
Fetches data from Spring Data REST API. Provided URL can be absolute or relative.
Fields keys to sort or to filter assumed to be passed to server without modifications.
Convert "virtual" fields to server ones before providing fetchArgs
to function.
responseCollectionKey
is the name of result collection element inside of _embedded
structure in response.
springDataRestResponseToPage
import { springDataRestResponseToPage } from '@vlsergey/react-bootstrap-pagetable';
interface SpringDataApiResponseType<K extends string, T> {
_embedded: {
[P in K]: T[];
};
page: {
size: number;
totalElements: number;
totalPages: number;
number: number;
};
}
function springDataRestResponseToPage<K extends string, T>(
key: K, response: SpringDataApiResponseType<K, T>
): Page<T>
Converts Spring Data REST API response to Page structure expected by PageTable.
key
is the name of content collection in _embedded
structure.