Not a bug, but can we have an optional component inside the pager to show the total number of records in the entire list?
This is possible with a custom pagination component. We invite you to join the slack channel and ask for help there or on stack overflow. Thanks!
why close this? This should be a feature request. It would be really useful to see this in the pagination footer: Showing 11-21 of 50 total rows
Not perfect, but here's a very quick pass at modifying the default pagination component to add row counts in the above format:
import React, { Component } from 'react'
import classnames from 'classnames'
const defaultButton = props => (
<button type="button" {...props} className="-btn">
{props.children}
</button>
)
export default class CBReactTablePagination extends Component {
constructor (props) {
super()
this.getSafePage = this.getSafePage.bind(this)
this.changePage = this.changePage.bind(this)
this.applyPage = this.applyPage.bind(this)
this.updateCurrentRows(props)
this.state = {
page: props.page
}
}
componentWillReceiveProps (nextProps) {
this.setState({ page: nextProps.page })
this.updateCurrentRows(nextProps)
}
updateCurrentRows(props) {
if ( typeof props.sortedData !== 'undefined' //use props.data for unfiltered (all) rows
&& typeof props.page !== 'undefined'
&& typeof props.pageSize !== 'undefined'
){
this.rowCount = props.sortedData.length //use props.data.length for unfiltered (all) rows
this.rowMin = props.page * props.pageSize + 1
this.rowMax = Math.min((props.page + 1) * props.pageSize, this.rowCount)
}
}
getSafePage (page) {
if (isNaN(page)) {
page = this.props.page
}
return Math.min(Math.max(page, 0), this.props.pages - 1)
}
changePage (page) {
page = this.getSafePage(page)
this.setState({ page })
if (this.props.page !== page) {
this.props.onPageChange(page)
}
this.updateCurrentRows(page)
}
applyPage (e) {
if (e) { e.preventDefault() }
const page = this.state.page
this.changePage(page === '' ? this.props.page : page)
}
render () {
const {
// Computed
pages,
// Props
page,
showPageSizeOptions,
pageSizeOptions,
pageSize,
showPageJump,
canPrevious,
canNext,
onPageSizeChange,
className,
PreviousComponent = defaultButton,
NextComponent = defaultButton,
} = this.props
return (
<div
className={classnames(className, '-pagination')}
style={this.props.style}
>
<div className="-previous">
<PreviousComponent
onClick={() => {
if (!canPrevious) return
this.changePage(page - 1)
}}
disabled={!canPrevious}
>
{this.props.previousText}
</PreviousComponent>
</div>
<div className="-center">
<span className="-pageInfo">
{this.props.pageText}{' '}
{showPageJump
? <div className="-pageJump">
<input
type={this.state.page === '' ? 'text' : 'number'}
onChange={e => {
const val = e.target.value
const page = val - 1
if (val === '') {
return this.setState({ page: val })
}
this.setState({ page: this.getSafePage(page) })
}}
value={this.state.page === '' ? '' : this.state.page + 1}
onBlur={this.applyPage}
onKeyPress={e => {
if (e.which === 13 || e.keyCode === 13) {
this.applyPage()
}
}}
/>
</div>
: <span className="-currentPage">
{page + 1}
</span>}{' '}
{this.props.ofText}{' '}
<span className="-totalPages">{pages || 1}</span>
</span>
{(typeof this.rowCount !== 'undefined') ?
<span className="-rowInfo">{"Showing "}
<span className="-rowMin">{this.rowMin}</span>
{" - "}
<span className="-rowMax">{this.rowMax}</span>
{" of "}
<span className="-rowCount">{this.rowCount}</span>
{" total rows"}
</span>
: ''}
{showPageSizeOptions &&
<span className="select-wrap -pageSizeOptions">
<select
onChange={e => onPageSizeChange(Number(e.target.value))}
value={pageSize}
>
{pageSizeOptions.map((option, i) => (
// eslint-disable-next-line react/no-array-index-key
<option key={i} value={option}>
{option} {this.props.rowsText}
</option>
))}
</select>
</span>}
</div>
<div className="-next">
<NextComponent
onClick={() => {
if (!canNext) return
this.changePage(page + 1)
}}
disabled={!canNext}
>
{this.props.nextText}
</NextComponent>
</div>
</div>
)
}
}
Import the above and wherever you drop in a react-table just add
PaginationComponent={CBReactTablePagination} or whatever you want to call it
@Morasta - Thanks for sharing your script. That saved me a lot of time in my own implementation.
Since I am using filters on all of my columns, I wanted to output how many rows are actually showing on screen.
Thus, I changed one item in your updateCurrentRows method:
updateCurrentRows(props) {
if ( typeof props.data !== 'undefined'
&& typeof props.page !== 'undefined'
&& typeof props.pageSize !== 'undefined'
){
this.rowCount = props.sortedData.length
this.rowMin = props.page * props.pageSize + 1
this.rowMax = Math.min((props.page + 1) * props.pageSize, this.rowCount)
}
}
I am using "sortedData" array instead of the "data" array in this method. That array, at least as far as I can tell, contains only the filtered / sorted data.
This appears to do the trick if you only want the count of rows currently available under your filters.
Thanks again!
That's awesome, @aldefouw. I am also using filters in a couple places, thanks for sharing the change you made to use filtered counts! That'll be useful on my end.
I think maybe the first if check in your edit should be props.sortedData to make sure there's data in there (no results may cause errors?).
@Morasta - Thanks - glad it will be helpful.
I can definitely understand the logic of wanting to check against props.sortedData. I am very new to React Table so I cannot speak definitively on whether that would make a difference.
Is there ever a case where props.sortedData would be undefined but props.data wouldn't?
I haven't hit that case yet but I can see where the code would seem to make sense more if we were checking against sortedData.
Thanks to both @Morasta and @aldefouw for their work, very useful to me on a tight deadline here. Also very new to React-Table so this was a great example of how it can be extended.
@Morasta : Above custom pagination example was really helpful. Thank you.
Could you please let me know, if it's possible to add First & Last button functionality as well?
Because I tried to add 2 components for first and last buttons (similar to Next /Previous), but because of '-next' & '-previous' classes, and canNext & canPrevious, I have no idea how to add button texts & those flags. Because button texts are blank & no values for canFirst & canLast.
Could you please advice on this.
Thank you.
@dilushi : Glad you found it helpful!
Here's a rough addition of first and last buttons. I repurposed the Previous and Next components and changed which page they reference for navigation.
import React, { Component } from 'react'
import classnames from 'classnames'
// import _ from './utils'
/*
Custom react table pagination with row count support
Based on core component: https://github.com/react-tools/react-table/blob/master/src/pagination.js
*/
const defaultButton = props => (
<button type="button" {...props} className="-btn">
{props.children}
</button>
)
export default class CBReactTablePagination extends Component {
constructor (props) {
super()
this.getSafePage = this.getSafePage.bind(this)
this.changePage = this.changePage.bind(this)
this.applyPage = this.applyPage.bind(this)
this.updateCurrentRows(props)
this.state = {
page: props.page
}
}
componentWillReceiveProps (nextProps) {
this.setState({ page: nextProps.page })
this.updateCurrentRows(nextProps)
}
updateCurrentRows(props) {
if ( typeof props.sortedData !== 'undefined'
&& typeof props.page !== 'undefined'
&& typeof props.pageSize !== 'undefined'
){
this.rowCount = props.sortedData.length
this.rowMin = props.page * props.pageSize + 1
this.rowMax = Math.min((props.page + 1) * props.pageSize, this.rowCount)
}
}
getSafePage (page) {
if (isNaN(page)) {
page = this.props.page
}
return Math.min(Math.max(page, 0), this.props.pages - 1)
}
changePage (page) {
page = this.getSafePage(page)
this.setState({ page })
if (this.props.page !== page) {
this.props.onPageChange(page)
}
this.updateCurrentRows(page)
}
applyPage (e) {
if (e) { e.preventDefault() }
const page = this.state.page
this.changePage(page === '' ? this.props.page : page)
}
render () {
const {
// Computed
pages,
// Props
page,
showPageSizeOptions,
pageSizeOptions,
pageSize,
showPageJump,
canPrevious,
canNext,
onPageSizeChange,
className,
PreviousComponent = defaultButton,
NextComponent = defaultButton,
} = this.props
return (
<div
className={classnames(className, '-pagination')}
style={this.props.style}
>
<div className="-first">
<PreviousComponent
onClick={() => {
if (!canPrevious) return
this.changePage(0)
}}
disabled={!canPrevious}
>
{'|<'}
</PreviousComponent>
</div>
<div className="-previous">
<PreviousComponent
onClick={() => {
if (!canPrevious) return
this.changePage(page - 1)
}}
disabled={!canPrevious}
>
{this.props.previousText}
</PreviousComponent>
</div>
<div className="-center">
<span className="-pageInfo">
{this.props.pageText}{' '}
{showPageJump
? <div className="-pageJump">
<input
type={this.state.page === '' ? 'text' : 'number'}
onChange={e => {
const val = e.target.value
const page = val - 1
if (val === '') {
return this.setState({ page: val })
}
this.setState({ page: this.getSafePage(page) })
}}
value={this.state.page === '' ? '' : this.state.page + 1}
onBlur={this.applyPage}
onKeyPress={e => {
if (e.which === 13 || e.keyCode === 13) {
this.applyPage()
}
}}
/>
</div>
: <span className="-currentPage">
{page + 1}
</span>}{' '}
{this.props.ofText}{' '}
<span className="-totalPages">{pages || 1}</span>
</span>
{(typeof this.rowCount !== 'undefined') ?
<span className="-rowInfo">{"Showing "}
<span className="-rowMin">{this.rowMin}</span>
{" - "}
<span className="-rowMax">{this.rowMax}</span>
{" of "}
<span className="-rowCount">{this.rowCount}</span>
{" total rows"}
</span>
: ''}
{showPageSizeOptions &&
<span className="select-wrap -pageSizeOptions">
<select
onChange={e => onPageSizeChange(Number(e.target.value))}
value={pageSize}
>
{pageSizeOptions.map((option, i) => (
// eslint-disable-next-line react/no-array-index-key
<option key={i} value={option}>
{option} {this.props.rowsText}
</option>
))}
</select>
</span>}
</div>
<div className="-next">
<NextComponent
onClick={() => {
if (!canNext) return
this.changePage(page + 1)
}}
disabled={!canNext}
>
{this.props.nextText}
</NextComponent>
</div>
<div className="-last">
<NextComponent
onClick={() => {
if (!canNext) return
this.changePage(pages)
}}
disabled={!canNext}
>
{'>|'}
</NextComponent>
</div>
</div>
)
}
}
And some quick and dirty CSS to get ya started:
/* Pagination */
.ReactTable .-pagination .-first {
margin-right: 3px;
}
.ReactTable .-pagination .-last {
margin-left: 3px;
}
please let me know, how can i added optional totalPages ?
example server response :
{
data: [
{id: 0},{id: 1},{id: 2},{id: 3},{id: 4},{id: 5}
],
pages: { totalPages: 10 }
}
i want show "Page 1 of 10" with 5 rows 5 records but i can't custom totalPages
@dilushi : Glad you found it helpful!
Here's a rough addition of first and last buttons. I repurposed the Previous and Next components and changed which page they reference for navigation.
import React, { Component } from 'react' import classnames from 'classnames' // import _ from './utils' /* Custom react table pagination with row count support Based on core component: https://github.com/react-tools/react-table/blob/master/src/pagination.js */ const defaultButton = props => ( <button type="button" {...props} className="-btn"> {props.children} </button> ) export default class CBReactTablePagination extends Component { constructor (props) { super() this.getSafePage = this.getSafePage.bind(this) this.changePage = this.changePage.bind(this) this.applyPage = this.applyPage.bind(this) this.updateCurrentRows(props) this.state = { page: props.page } } componentWillReceiveProps (nextProps) { this.setState({ page: nextProps.page }) this.updateCurrentRows(nextProps) } updateCurrentRows(props) { if ( typeof props.sortedData !== 'undefined' && typeof props.page !== 'undefined' && typeof props.pageSize !== 'undefined' ){ this.rowCount = props.sortedData.length this.rowMin = props.page * props.pageSize + 1 this.rowMax = Math.min((props.page + 1) * props.pageSize, this.rowCount) } } getSafePage (page) { if (isNaN(page)) { page = this.props.page } return Math.min(Math.max(page, 0), this.props.pages - 1) } changePage (page) { page = this.getSafePage(page) this.setState({ page }) if (this.props.page !== page) { this.props.onPageChange(page) } this.updateCurrentRows(page) } applyPage (e) { if (e) { e.preventDefault() } const page = this.state.page this.changePage(page === '' ? this.props.page : page) } render () { const { // Computed pages, // Props page, showPageSizeOptions, pageSizeOptions, pageSize, showPageJump, canPrevious, canNext, onPageSizeChange, className, PreviousComponent = defaultButton, NextComponent = defaultButton, } = this.props console.log("pagination props") console.log(this.props) return ( <div className={classnames(className, '-pagination')} style={this.props.style} > <div className="-first"> <PreviousComponent onClick={() => { if (!canPrevious) return this.changePage(0) }} disabled={!canPrevious} > {'|<'} </PreviousComponent> </div> <div className="-previous"> <PreviousComponent onClick={() => { if (!canPrevious) return this.changePage(page - 1) }} disabled={!canPrevious} > {this.props.previousText} </PreviousComponent> </div> <div className="-center"> <span className="-pageInfo"> {this.props.pageText}{' '} {showPageJump ? <div className="-pageJump"> <input type={this.state.page === '' ? 'text' : 'number'} onChange={e => { const val = e.target.value const page = val - 1 if (val === '') { return this.setState({ page: val }) } this.setState({ page: this.getSafePage(page) }) }} value={this.state.page === '' ? '' : this.state.page + 1} onBlur={this.applyPage} onKeyPress={e => { if (e.which === 13 || e.keyCode === 13) { this.applyPage() } }} /> </div> : <span className="-currentPage"> {page + 1} </span>}{' '} {this.props.ofText}{' '} <span className="-totalPages">{pages || 1}</span> </span> {(typeof this.rowCount !== 'undefined') ? <span className="-rowInfo">{"Showing "} <span className="-rowMin">{this.rowMin}</span> {" - "} <span className="-rowMax">{this.rowMax}</span> {" of "} <span className="-rowCount">{this.rowCount}</span> {" total rows"} </span> : ''} {showPageSizeOptions && <span className="select-wrap -pageSizeOptions"> <select onChange={e => onPageSizeChange(Number(e.target.value))} value={pageSize} > {pageSizeOptions.map((option, i) => ( // eslint-disable-next-line react/no-array-index-key <option key={i} value={option}> {option} {this.props.rowsText} </option> ))} </select> </span>} </div> <div className="-next"> <NextComponent onClick={() => { if (!canNext) return this.changePage(page + 1) }} disabled={!canNext} > {this.props.nextText} </NextComponent> </div> <div className="-last"> <NextComponent onClick={() => { if (!canNext) return this.changePage(pages) }} disabled={!canNext} > {'>|'} </NextComponent> </div> </div> ) } }And some quick and dirty CSS to get ya started:
/* Pagination */ .ReactTable .-pagination .-first { margin-right: 3px; } .ReactTable .-pagination .-last { margin-left: 3px; }
Thanks, this code is very useful.
Don't you want to add this feature? It's still needed by users
Most helpful comment
why close this? This should be a feature request. It would be really useful to see this in the pagination footer:
Showing 11-21 of 50 total rows