#

In 

# :keynav_js


:keynav_js is a fast KEYSET paginator that supports the UI. It's a pagy exclusive technique.

  • It requires JavaScript Support and a browser that implements sessionStorage (largely supported by all browsers).
    • If those conditions are not met, it falls back to the :countless paginator seamlessly.
Controller
@pagy, @records = pagy(:keynav_js, collection, **options)
  • @pagy is the pagination instance. It provides the readers and the helpers to use in your code.
  • @records is the eager-loaded Array of the page records.

Try it now!

See also Keyset Readers

Integrates the Keyset Glossary

Term Description
keynav pagination The pagy exclusive technique to use keyset pagination, providing nearly complete support for most navigation helpers. The fasted technique with UI capabilities.
page The array of options from the client prepared by the keynav_js, to paginate the requested page.
cutoffs The array of cutoffs of the known pagination state, used to keep track of the visited pages during the navigation. They are cached in the sessionStorage of the client.

The Keynav pagination adds the numeric variables (@page, @last, @prev, @next, @in) to its instances, supporting their usage with the UI. It does so by transparently exchanging data with the client, that stores the state of the pagination.

You can use the :keyset_js paginator as you would use the :countless paginator. You just need the Keyset Setup and JavaScript Support, to get a lot more performance.

Let's take a new look at the diagram of the keyset pagination explained in the Keyset documentation:

                  │ first page (10)  >│ second page (10) >│ last page (9)  >│
beginning of set >[· · · · · · · · · X]· · · · · · · · · Y]· · · · · · · · ·]< end of set
                                      â–²                   â–²
                                   cutoff-X            cutoff-Y

Let's suppose that we navigate till page #3 (i.e., the last page), and we click on the link for page #2. We have stored the cutoff-X, so we can pull the 10 records after cutoff-X again as we did the first time... but are we sure that we would get the same results?

Let's suppose that the database just changed: 1 record was inserted before cutoff-X, and 2 records were deleted after cutoff-X...

                  │ page #1 (11)       >│ page #2 (8)  >│ page #3 (9)    >│
beginning of set >[· · · · · · · · · · X]· · · · · · · Y]· · · · · · · · ·]< end of set
                                        â–²               â–²
                                   cutoff-X        cutoff-Y

At this point pulling 10 records from the cutoff-X would get also the first 2 records from page 3, if you navigate on page 3 you will pull the same 2 records again also for page #3.

Indeed, not only the results have changed, but the cutoffs appear to have also shifted their absolute position in the set. In reality the cutoffs have the same value as before, so they maintained their relative position in the set, and now there is a different number of records falling into the same pages, which is totally consistent with the changes, but possibly unespected if you have the mindset of OFFSET pagination, where the pages are split by number of records (absolute position) and not by their position relative to the records in the set.

Pagy doesn't use the LIMIT to pull the records of already visited pages. Instead, it replaces the LIMIT with the same filter used for the beginning of the page, but it just compounds it with the negated filter of the ending of the page.

For example, the filtering of the page could be logically described like:

- Page #1 `WHERE NOT AFTER CUTOFF-X`                    <- only ending filter
- Page #2 `WHERE AFTER CUTOFF-X AND NOT AFTER CUTOFF-Y` <- combined beginning + ending filter
- Page #3 `WHERE AFTER CUTOFF-Y LIMIT 10`               <- regular beginning filter (no cutoff for last page)

Nav bar links beyond the last or highest visited page are not displayed.