Search code examples
javascriptreactjstypescriptecmascript-6pagination

Want to dynamically handle display of page numbers with respect to Pagination : ReactJS


I have some pagination logic working just fine, only issue is I can only get it to show and fixed number of pages to choose from. Right now I have put it to 5 pages, but I would like it to change dynamically based on total records..

So lets say I have 100 records and the limit per page is 10 . There will be 10 pages. Right now I can only get it to show this way

First Prev 1 2 3 4 5 6 7 8 9 10 Next Last

But what I want is the paging to change dynamically based on records and based on what page you are at.

So it looks more like this:

At page 1: 1 2 3 4 5 Next Last

At page 5: First Prev 3 4 5 6 7 Next Last

At page 3: First Prev 1 2 3 4 5 Next Last

I have tried a lot of things, but can not seem to find the right solution. Can someone tell me how to do on current code I have ?

Help would be really appreciated.

Link to the sandbox: https://codesandbox.io/s/react-typescript-nvffv

App Component


    import * as React from "react";
    import Pagination from "./Pagination";
    import * as ReactDOM from "react-dom";
    const NO_OF_RECORDS_PER_PAGE = 10;

    interface IState {
      length: number;
      currentPage: number;
    }

    interface IProps {}
    export default class App extends React.Component<IProps, IState> {
      constructor(props: any) {
        super(props);
        this.state = {
          length: 0,
          currentPage: 1
        };
      }

      componentDidMount() {
        this.setState({ length: 98 });
      }

      handlePagination = (fromIndex: number, noOfRecords: number) => {
        //Pagination logic here 
        //console.log(fromIndex, noOfRecords);
      };

      render() {
        return (
          <Pagination
            dataCount={this.state.length}
            currentPage={this.state.currentPage}
            handlePagination={this.handlePagination}
            perPageCount={NO_OF_RECORDS_PER_PAGE}
          />
        );
      }
    }

    const rootElement = document.getElementById("root");
    ReactDOM.render(<App />, rootElement);

Pagination Component


    import * as React from "react";
    interface IProps {
      dataCount: number;
      handlePagination(fromIndex: number, noOfRecords: number): any;
      perPageCount: number;
    }

    interface IState {
      pages: number;
      fromIndex: number;
      currentPage: number;
    }

    export default class PaginationComponent extends React.Component<
      IProps,
      IState
    > {
      constructor(props: any) {
        super(props);
        this.state = {
          pages: this.findNumberOfPages(),
          fromIndex: 0,
          currentPage: 1
        };
      }

      componentDidUpdate(prevProps: any) {
        if (prevProps.dataCount !== this.props.dataCount) {
          this.setState({ pages: this.findNumberOfPages() });
        }
      }

      findNumberOfPages = () => {
        return Math.ceil(this.props.dataCount / this.props.perPageCount);
      };

      setOffset = (value: number) => {
        let fromIndex = this.getFromIndex(
          value,
          this.props.perPageCount,
          this.props.dataCount
        );
        this.setState({ fromIndex, currentPage: value }, () =>
          this.props.handlePagination(this.state.fromIndex, this.props.perPageCount)
        );
      };

      getFromIndex = (page_no: number, per_page: number, total_length: number) => {
        return (
          +page_no &&
          +page_no <= Math.ceil(total_length / per_page) &&
          per_page * --page_no
        );
      };

      renderPageNumbers = () => {
        const numberOfPages = this.findNumberOfPages();
        let pages = [];
        for (let i = 1; i <= numberOfPages; i++) {
          pages.push(
            <span
              key={i}
              className="margin-wd-10"
              onClick={() => this.setOffset(i)}
              style={{ cursor: "pointer" }}
            >
              {i}&nbsp;&nbsp;
            </span>
          );
        }
        return pages;
      };

      renderPrevButton = () => {
        return (
          <>
            {this.state.currentPage > 1 ? (
              <button
                style={{ cursor: "pointer" }}
                onClick={() => this.setOffset(this.state.currentPage - 1)}
              >
                &lt;
              </button>
            ) : (
              <button style={{ cursor: "pointer" }} disabled>
                &lt;
              </button>
            )}
          </>
        );
      };

      renderNextButton = () => {
        return (
          <>
            {this.state.currentPage < this.state.pages ? (
              <button
                style={{ cursor: "pointer" }}
                onClick={() => this.setOffset(this.state.currentPage + 1)}
              >
                &gt;
              </button>
            ) : (
              <button style={{ cursor: "pointer" }} disabled>
                &gt;
              </button>
            )}
          </>
        );
      };

      renderFirstButton = () => {
        return (
          <>
            {this.state.currentPage > 1 ? (
              <button
                style={{ cursor: "pointer" }}
                onClick={() => this.setOffset(1)}
              >
                First
              </button>
            ) : (
              <button style={{ cursor: "pointer" }} disabled>
                First
              </button>
            )}
          </>
        );
      };

      renderLastButton = () => {
        return (
          <>
            {this.state.currentPage < this.state.pages ? (
              <button
                style={{ cursor: "pointer" }}
                onClick={() => this.setOffset(this.state.pages)}
              >
                Last
              </button>
            ) : (
              <button style={{ cursor: "pointer" }} disabled>
                Last
              </button>
            )}
          </>
        );
      };

      render() {
        return (
          <>
            <div>
              {this.renderFirstButton()}
              &nbsp;
              {this.renderPrevButton()}
              &nbsp;
              {this.renderPageNumbers()}
              {this.renderNextButton()}
              &nbsp;
              {this.renderLastButton()}
            </div>
          </>
        );
      }
    }



Solution

  • Check if this works for you. I've changed the renderPageNumbers so that it only displays from currentPage to currentPage + 5. The 5 here is random. You can choose any window. Or pass it from a prop to make it more dynamic.

     renderPageNumbers = () => {
        const numberOfPages = this.findNumberOfPages();
        let pages = [];
        const {currentPage} = this.state;
        for (
           let i = currentPage; 
           (i <= currentPage + 4) && (i < numberOfPages);
            i++
           ) {
          pages.push(
            <span
              key={i}
              className="margin-wd-10"
              onClick={() => this.setOffset(i)}
              style={{ cursor: "pointer" }}
            >
              {i}&nbsp;&nbsp;
            </span>
          );
        }
        return pages;
      };
    

    The link to sand box. I don't know if it's saved or not. https://codesandbox.io/s/react-typescript-b220b