Pagination is essential for providing a smooth user experience when displaying large sets of search results. Instead of overwhelming users with all the results at once, pagination breaks the results into manageable chunks or pages. This approach reduces load time, makes navigation easier, and improves performance.
Here’s how you can implement pagination for search results in Power Pages:
Approach 1: Client-Side Pagination Using JavaScript
This is a client-side solution where you already have the search results available in the page (either through Liquid rendering or client-side APIs) and then implement pagination directly in JavaScript.
Step 1: Render Data with Liquid
First, you need to output the data into the HTML structure. Let’s say you’re rendering a list of articles from Dataverse.
<ul id="articleList">
{% fetchxml articles %}
<fetch>
<entity name="knowledgearticle">
<attribute name="title" />
<attribute name="description" />
<attribute name="createdon" />
</entity>
</fetch>
{% endfetchxml %}
{% for article in articles.results.entities %}
<li class="article-item" data-title="{{ article.title }}">
<h4>{{ article.title }}</h4>
<p>{{ article.description }}</p>
</li>
{% endfor %}
</ul>
<!-- Pagination controls -->
<div id="paginationControls">
<button id="prevPage">Previous</button>
<button id="nextPage">Next</button>
</div>
Step 2: Add Pagination Logic with JavaScript
Now, implement the pagination logic using JavaScript. This will divide the results into pages and only display a subset at a time.
<script>
document.addEventListener("DOMContentLoaded", function () {
const articlesPerPage = 5; // Number of results per page
let currentPage = 1;
const listContainer = document.getElementById("articleList");
const allArticles = Array.from(listContainer.querySelectorAll(".article-item"));
const totalPages = Math.ceil(allArticles.length / articlesPerPage);
// Function to display the correct articles for the current page
function paginateArticles() {
// Calculate the start and end index for the articles to display
const start = (currentPage - 1) * articlesPerPage;
const end = start + articlesPerPage;
// Hide all articles
allArticles.forEach(article => article.style.display = "none");
// Display only the articles for the current page
allArticles.slice(start, end).forEach(article => article.style.display = "block");
// Disable previous button if we're on the first page
document.getElementById("prevPage").disabled = currentPage === 1;
// Disable next button if we're on the last page
document.getElementById("nextPage").disabled = currentPage === totalPages;
}
// Add event listeners for pagination buttons
document.getElementById("prevPage").addEventListener("click", function () {
if (currentPage > 1) {
currentPage--;
paginateArticles();
}
});
document.getElementById("nextPage").addEventListener("click", function () {
if (currentPage < totalPages) {
currentPage++;
paginateArticles();
}
});
// Initialize pagination
paginateArticles();
});
</script>
Explanation:
- Articles Per Page: Set the number of items to show on each page (
articlesPerPage
). - Pagination Buttons: “Next” and “Previous” buttons allow the user to navigate between pages.
- Pagination Logic:
- The script calculates which articles should be displayed based on the current page number.
- It hides all articles initially and then displays only the relevant ones.
- Disabling Buttons: The “Previous” button is disabled when the user is on the first page, and the “Next” button is disabled when they are on the last page.
Approach 2: Server-Side Pagination (via FetchXML)
For large datasets, it’s better to implement server-side pagination where only the records for the current page are fetched from the server. This reduces load time and enhances performance.
Here’s how you can implement pagination with FetchXML in Power Pages:
Step 1: Liquid with FetchXML Pagination
In this example, we add page number and page size parameters to the FetchXML query to fetch only a subset of records per page.
{% assign pageSize = 5 %}
{% assign pageNumber = request.params['page'] | default: 1 %}
{% assign skip = pageSize * (pageNumber - 1) %}
{% fetchxml articles %}
<fetch>
<entity name="knowledgearticle">
<attribute name="title" />
<attribute name="description" />
<attribute name="createdon" />
<order attribute="createdon" descending="true" />
<page size="{{ pageSize }}" page="{{ pageNumber }}" />
</entity>
</fetch>
{% endfetchxml %}
{% for article in articles.results.entities %}
<li>{{ article.title }} - {{ article.description }}</li>
{% endfor %}
Step 2: Implement Pagination Controls
After rendering the search results, create pagination controls that allow the user to navigate between pages.
<div id="paginationControls">
{% if pageNumber > 1 %}
<a href="?page={{ pageNumber - 1 }}">Previous</a>
{% endif %}
{% if articles.results.entities.size == pageSize %}
<a href="?page={{ pageNumber + 1 }}">Next</a>
{% endif %}
</div>
Explanation:
<page size="X" page="Y">
: FetchXML supports paging withpage
andsize
parameters. The page number and size are dynamically adjusted based on the user’s navigation.- Pagination Controls: Based on the current page and the number of results, we show “Previous” and “Next” buttons. The “Next” button is displayed if the current page has the maximum number of items (
pageSize
).
Best Practices for Pagination
- Limit Results per Page: Set an appropriate
pageSize
to avoid overwhelming users and to optimize page load times. - Consistent Navigation: Ensure that pagination buttons are always visible and properly linked to the next/previous pages.
- Loading Indicators: For larger datasets, consider adding a loading spinner to show when new data is being fetched.
- Server-Side Pagination: Use server-side pagination for large datasets to minimize data transfer and reduce client-side load.