Results 1 to 7 of 7

Thread: Pagination Logic

  1. #1

    Thread Starter
    Super Moderator dday9's Avatar
    Join Date
    Mar 2011
    Location
    South Louisiana
    Posts
    11,755

    Pagination Logic

    I need help figuring out the logic behind my pagination code. I am using JavaScript, but this can apply to any language because it is the logic behind it that I need help with.

    Assume I want to show a "first" button, "last" button, and then up to 5 page buttons in the middle. This is what I have so far:
    1. If there are 1 or no records, disable the first and last buttons then do not show any buttons in the middle.
    2. If there are 2 records:
      1. Disable the first button if the current "page" is 1
      2. Disable the last button if the current "page" is 2
    3. If there are 3 or more records:
      1. Loop over the next 5 records -or- the next n records
        1. If there are 3 records then only show page 2, if the current page is 2 then disable page 2
        2. If there are 4 records then only show pages 2 and 3, if the current page is 2 or 3 then disable the respective page
        3. If there are 5 records then only show pages 2, 3, and 4, if the current page is 2, 3, or 4 then disable the respective page
        4. If there are 6 records then only show pages 2, 3, 4, and 5, if the current page is 2, 3, 4, or 5 then disable the respective page
        5. If there are 7 records then only show pages 2, 3, 4, 5, and 6, if the current page is 2, 3, 4, 5, or 6 then disable the respective page
        6. If there are 8 or more records then show the current page in the middle and +/- 2 pages and disable the current page (in the middle)


    What I am getting hung up on is step 3a. I understand that I can build in the if statements for steps 3.a.i - 3.a.vi, but it feels redundant. Is there anyway that I can accomplish this without having 6 conditional checks when I go to build the page numbers (i.e. not the first/last buttons)?

    For what it is worth, here is my (heavily commented) code:
    Code:
    const buildPagination = (messages, currentPage) => {
        // if no currentPage argument is specified, assume we are starting on page 1 (aka the first page)
        currentPage = currentPage || 1;
    
        // get the parent DOM element that holds the unordered list
        const messagesPagination = document.getElementById('messages-pagination');
    
        // get the parent DOM element that is the unordered list that holds the page items
        const unorderedList = messagesPagination.querySelector('.pagination');
    
        // get the first/last buttons and optionally any existing page number items
        const existingMessagesPaginations = document.querySelectorAll('.messages-pagination');
        const messagesPaginationFirst = document.getElementById('messages-pagination-first');
        const messagesPaginationLast = document.getElementById('messages-pagination-last');
    
        // loop over the page number items to remove them
        for (let existingMessagesPagination of existingMessagesPaginations) {
            existingMessagesPagination.remove();
        }
    
        // solves step 1 in business logic
        if (messages.length < 2) {
            if (!messagesPaginationFirst.classList.contains('disabled')) {
                messagesPaginationFirst.classList.add('disabled');
            }
            if (!messagesPaginationLast.classList.contains('disabled')) {
                messagesPaginationLast.classList.add('disabled');
            }
            return;
        }
    
        // solves step 2a in business logic
        if (currentPage === 1 && !messagesPaginationFirst.classList.contains('disabled')) {
            messagesPaginationFirst.classList.add('disabled');
        } else if (currentPage !== 1 && messagesPaginationFirst.classList.contains('disabled')) {
            messagesPaginationFirst.classList.remove('disabled');
        }
    
        // solves step 2b in business logic
        if (currentPage === messages.length && !messagesPaginationLast.classList.contains('disabled')) {
            messagesPaginationLast.classList.add('disabled');
        } else if (currentPage !== messages.length && messagesPaginationLast.classList.contains('disabled')) {
            messagesPaginationLast.classList.remove('disabled');
        }
    
        // my (failed) attempt at step 3
        const upperBounds = currentPage + 6 >= messages.length - 1 ? 6 - currentPage - 2 : 6;
        for (let index = 1; index <= upperBounds; index++) {
            const currentlyIteratedPage = index + currentPage;
            const listItem = buildPaginationItem(messages[currentlyIteratedPage], currentlyIteratedPage);
            unorderedList.appendChild(listItem);
            listItem.addEventListener('click', messagesPagination_Click, false);
        }
        unorderedList.appendChild(messagesPaginationLast);
    };
    Any help is appreciated. Pseudo code, c-style syntax, BASIC style syntax, I don't really care. I just need help fleshing out this logic
    "Code is like humor. When you have to explain it, it is bad." - Cory House
    VbLessons | Code Tags | Sword of Fury - Jameram

  2. #2
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,930

    Re: Pagination Logic

    As you want "up to 5 page buttons", my logic for 2-5 pages would be:
    1. Disable the first button if the current "page" is 1
    2. Disable the last button if the current "page" is the last page
    3. Display page buttons for all pages (1-n), and disable the current page.


    For more than 5 pages, that last step changes a little as you need to determine which page buttons to show (rather than just showing all). To do this:
    1. If the current page is 3 or less, show page buttons 1 to 5.
    2. If the current page is (number-of-pages) - 2 or higher, show page buttons (number-of-pages)-4 to (number-of-pages).
    3. Otherwise, show page buttons (current-page) - 2 to (current-page) + 2.

  3. #3
    Fanatic Member
    Join Date
    Jun 2019
    Posts
    558

    Re: Pagination Logic

    You can do it more generic by defining the number of page buttons shown as your requirement may change in future. Take for example forum software where on top the paging is more simpler showing only 5 page numbers but on bottom it may list much more page numbers as user most of times wants to change to other page after reviewing current and is already at the bottom. Showing more page buttons at the bottom gives more choice to the user. And you can generate these page button sets using same routine with just different parameters (max page buttons, number of pages, current page, max button set width, etc.). Start simple and add more and more edge cases and you will get it right.

    When exact number of pages is not very useful - just have first-prev and next-last buttons for changing pages. User will just move to next page after reviewing results from current page. It could be that rarely (or never) user wants to move to exact page number.

    In many cases paging is not possible if the total number of items to show could change with time. And moving to page may miss items or show items from previous shown page when there are added or removed items by other users while the user is checking the content of items in single page.

    Other times the total number of items in the list (with or without filtering items) could be very slow to be retrieved. Some UI design changes were invented to make users "not wait" for data: endless scrolling on mobile devices, load more (or next NN) items when you reach the end of "current page" and so on.

    There are some some tricks to avoid some of the problems above - retrieve data for next pages using timestamp with initial (first) page retrieval; pre-cache next page items; generate query token (or use the timestamp as token) which will not change during pages retrieval and use it with same query parameters; retrieve and cache on server first 10 pages (but return first page content only) and then in background continue retrieval of next N pages on server mem cache so next page results for next 10+N pages will be almost instant and do retrieve to keep 10+N pages upfront of each new page from same query session and so on.

  4. #4
    PowerPoster Zvoni's Avatar
    Join Date
    Sep 2012
    Location
    To the moon and then left
    Posts
    4,440

    Re: Pagination Logic

    hmmm.....what about determining upfront how many pages you need?

    e.g. you have 100 Records, and want to show 15 Records per page

    1) Integerdivision of Records by Rec/Page --> 100 Div 15 --> Result = 6
    2) Check if remain is zero --> 100 Mod 15 --> Result = 10 --> Add one page (If Result = 0 you don't add a page)
    3) Assign records to their pages --> 2D-Array? in the sample Pages(1 To 7, 1 To 15) (VB-Notation)

    in the sample you would need 7 pages.

    Let's say you want to display something of a navigation-bar looking like

    First | 2 | 3 | 4 | ... | Last

    User clicks on 4 -->
    First | ... | 3 | 4 | 5 | ... | Last

    You would just have to check, where in the Index-Array you are and calculate the "distance" to the beginning and end to decide "disabling First/Last"

    EDIT: I think i got your problem now.
    You want to display 1 Record per Page (like a DB-navigator)

    To stay in your Sample
    First and Last plus max. 5 buttons --> Max. 7 Buttons

    RecordCount=RC

    RC Div 7 -->
    If this is Zero you check RC Mod 7 --> This Result handles your point 3 a i. - v.
    like:
    Constant FirstNumberedButton=2
    ModResult=RC Mod 7
    AmountButtons=ModResult-2
    LastNumberedButton=ModResult-1
    Show "First", Show From FirstNumberedButton To LastNumberedButton, Show "Last"

    If RC Div 7 is >0 then you are at 3 a vi.
    Here you would have to change "FirstNumberedButton" to your "+/- 2 Pages around current page" to get a starting point which is easy to calculate

    btw: With CurrentPage Mod 7 (or along this line. Not sure) you also get the Button which to disable, since there are only 7 buttons max.
    Sanity checks have to be made though

    EDIT2: Food for thought
    Imagine having 9 (or more) Records/Pages
    MaxButtons would (should?) be 9 (!!)
    First | ... | 3 | 4 | 5 | 6 | 7 | ... | Last
    Last edited by Zvoni; Aug 17th, 2022 at 01:56 AM.
    Last edited by Zvoni; Tomorrow at 31:69 PM.
    ----------------------------------------------------------------------------------------

    One System to rule them all, One Code to find them,
    One IDE to bring them all, and to the Framework bind them,
    in the Land of Redmond, where the Windows lie
    ---------------------------------------------------------------------------------
    People call me crazy because i'm jumping out of perfectly fine airplanes.
    ---------------------------------------------------------------------------------
    Code is like a joke: If you have to explain it, it's bad

  5. #5
    Fanatic Member
    Join Date
    Jun 2019
    Posts
    558

    Re: Pagination Logic

    Some examples from from forums.

    First page is current one:
    Code:
    1  2  3  4  5  ...  >  >|
    Last page is current one:
    Code:
    |<  <   ...  100 101 102
    Multi-page thread somewhere in the middle:
    Code:
    |< <  ... 5 505 905 955 995 1002 1003 1004 1005 1006 1007 1008 1015 1055 1105 1505 ... > >|
    This one is from Post Race! thread page 1005. The buttons are more than 5, but pages are spread to quickly access not only neighbours but also further ones with increased distance.

    Navigation UX should be designed to help users. The last example is on the extreme but IMO it confuses more than helps. But also limiting how far can the user jump with single button/link click is also not helping for advanced users.

    Some apps were designed with text box where user can enter page number to jump to. Others have additional buttons -10 and +10 to allow longer jumps. Everything depends on type of data shown, expected number of items and the workflow that users will have.

  6. #6
    King of sapila
    Join Date
    Oct 2006
    Location
    Greece
    Posts
    6,605

    Re: Pagination Logic

    If this is a self project for recreation issues then OK but if not, why reinvent the wheel?
    So some examples with a quick search:
    https://webdesign.tutsplus.com/tutor...ipt--cms-41896
    https://www.cssscript.com/tag/pagination/
    https://www.jqueryscript.net/blog/be...n-plugins.html
    https://www.edureka.co/blog/pagination-in-angular-js/

    Note Jquery is deprecated but I included it just in case you are using it.
    ἄνδρα μοι ἔννεπε, μοῦσα, πολύτροπον, ὃς μάλα πολλὰ
    πλάγχθη, ἐπεὶ Τροίης ἱερὸν πτολίεθρον ἔπερσεν·

  7. #7
    PowerPoster Zvoni's Avatar
    Join Date
    Sep 2012
    Location
    To the moon and then left
    Posts
    4,440

    Re: Pagination Logic

    EDIT2: Food for thought
    Imagine having 9 (or more) Records/Pages
    MaxButtons would (should?) be 9 (!!)
    First | ... | 3 | 4 | 5 | 6 | 7 | ... | Last
    Just remembered something:
    In a case like above, meaning you're currently navigating way far from your "margins",
    the button to be disabled is always the one in the middle....
    Last edited by Zvoni; Tomorrow at 31:69 PM.
    ----------------------------------------------------------------------------------------

    One System to rule them all, One Code to find them,
    One IDE to bring them all, and to the Framework bind them,
    in the Land of Redmond, where the Windows lie
    ---------------------------------------------------------------------------------
    People call me crazy because i'm jumping out of perfectly fine airplanes.
    ---------------------------------------------------------------------------------
    Code is like a joke: If you have to explain it, it's bad

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width