Pagination

What is pagination?

Sometimes you want to aggregate many individual pieces of content onto a single page. This is common for things like blog posts and event pages; there are many individual nodes, but one landing page that collects them all so people can browse what is available. If there are too many items to display on a single page, often times they are broken up into individual pages that people can cycle through by clicking a "next" or "previous" button (a pager). This increments the current page and loads a new set of items while clearing out the previous set.

Implementation

In your sitewide plenti.json configuration file, you can create pagination, for your homepage for example, like this:

{
  "routes": {
    "index": ":paginate(totalPages)"
  }
}

The value of totalPages in this example must be defined in the template for this route, which in this case is layouts/content/index.svelte. You have complete flexibility to set up your pagination to work in any way that you see fit. We don't force you to use any particular pattern, at build time we simply evaluate the value of whatever variable name you put in your route to determine how many server rendered pages you need. For example you might create pagination in your template to work with the route specified above like this:

<script>
  import Grid from '../components/grid.svelte';
  import Pager from '../components/pager.svelte';
  export let content, allContent;

  $: currentPage = content.pager ? content.pager : 1;
  let postsPerPage = 3;
  let allPosts = allContent.filter(content => content.type == "blog");
  let totalPosts = allPosts.length;
  let totalPages = Math.ceil(totalPosts / postsPerPage); // This is the variable you set in your route
  $: postRangeHigh = currentPage * postsPerPage;
  $: postRangeLow = postRangeHigh - postsPerPage;
</script>

<Grid {allPosts} {postRangeLow} {postRangeHigh} />
<Pager {currentPage} {totalPages} />

(Note: the content.pager ships with each node on your site to help keep track of which page you're on)

Displaying paged items

To display the correct items, you'll want to check if the position of the current post is within the expected range of the items that should be displayed. Keeping with the example above, you could create a layouts/components/grid.svelte file that looks something like this:

<script>
  export let allPosts, postRangeLow, postRangeHigh;
</script>

<div class='grid'>
  {#each allPosts as post, i}
    {#if i >= postRangeLow && i < postRangeHigh}
      <a class='grid-item' href='{post.path}'>{post.fields.title}</a>
    {/if}
  {/each}
</div>

Creating a pager

The pager is the actual controls used to navigate forward and backward through the paged output. You have ultimate flexibility of how this is implemented, but it might look something like this:

<script>
  export let currentPage, totalPages;
</script>

<ul>
  {#if currentPage > 1}
    <li><a href='.'>first</a></li>
    <li><a href='{currentPage - 1}'>prev</a></li>
  {:else}
    <li><span>first</span></li>
    <li><span>prev</span></li>
  {/if}
  {#each [3,2,1] as i}
    {#if currentPage - i > 0}
      <li><a href="{currentPage - i}">{currentPage - i}</a></li>
    {/if}
  {/each}
  <li><span>{currentPage}</span></li>
  {#each Array(3) as _, i}
    {#if currentPage + (i+1) <= totalPages}
      <li><a href="{currentPage + (i+1)}">{currentPage + (i+1)}</a></li>
    {/if}
  {/each}
  {#if currentPage < totalPages}
    <li><a href="{currentPage + 1}">next</a></li>
    <li><a href="{totalPages}">last</a></li>
  {:else}
    <li><span>next</span></li>
    <li><span>last</span></li>
  {/if}
</ul>