Thymeleaf re-usable pagination component- Spring MVC/Bootstrap

In this blog, we will discuss how we can create a reusable pagination component using Thymeleaf and Spring MVC/Data.

Goal is to create a pagination UI similar to this:

 

Controller 

Spring resolves the size and page parameter from URL : /users?size=20&page=1 to Pageable object at the Controller methods. We are returning Page<> instead of simple list. Page contains all the information that we need to create the pagination UI as above.
@GetMapping("/articles")
public String userHome(Model model, Pageable pageable) {
Page<Article> page= articleService.findAllByStatus(Status.PUBLISHED, pageable);
model.addAttribute("articles", page);
return "home-page";
}

@GetMapping("/users")
public String userHome(Model model, Pageable pageable) {
Page<User> page= userRepo.findAllByStatus(Status.ACTIVE, pageable);
model.addAttribute("users", page);
return "user-list";
}

 

Pagination at home-page.html   

<th:block th:each="article : ${articles}">
<!-- display article in a table row or card/box -->
</th:block>

<!--pager at bottom -->
<th:block th:replace="_fragments/_utils :: pagination(${articles})">
</th:block>

Pagination at user-list.html

<th:block th:each="user : ${users}">
<!-- display user in a table row or card/box -->
</th:block>
<!--pager at bottom -->
<th:block th:replace="_fragments/_utils :: pagination(${users})">
</th:block>

Reusable Fragment Definition at _fragments/_utils.html

Note that the pages are 0 based meaning page=0 equals the first page of data. You can make it to 1 based using the steps described here: https://ganeshtiwaridotcomdotnp.blogspot.com/2020/09/spring-pageable-start-index-with-one.html. You might also need to update the indices below to to handle that.

<th:block th:fragment="pagination(pagedObject)">

<!-- works with org.springframework.data.domain.Page<pagedObject>, -->

<div th:if="${pagedObject.getTotalPages() != 1}" class="form-group col-md-11 pagination-centered">
<ul class="pagination">
<!-- page number start with 0, totalPages returns actual number of pages -->
<li th:classappend="${pagedObject.getNumber() == 0} ? disabled" class="page-item">
<a class="page-link" th:href="@{''(size=${pagedObject.getSize()}, page=0)}">&laquo;</a>
</li>
<li th:classappend="${pagedObject.getNumber() == 0} ? disabled" class="page-item">
<a class="page-link"
th:href="@{''(size=${pagedObject.getSize()}, page=${pagedObject.getNumber() -1})}">&larr;</a>
</li>
<li th:classappend="${pagedObject.getNumber() == (page )} ? 'active pointer-disabled'"
th:each="page : ${#numbers.sequence(0, pagedObject.getTotalPages() -1)}" class="page-item">
<a class="page-link" th:href="@{''(size=${pagedObject.getSize()}, page=${page})}"
th:text="${page + 1}"></a>
</li>
<li th:classappend="${pagedObject.getNumber() + 1 == pagedObject.getTotalPages()} ? disabled"
class="page-item">
<a class="page-link"
th:href="@{''(size=${pagedObject.getSize()}, page=${pagedObject.getNumber() + 1})}">&rarr;</a>
</li>
<li th:classappend="${pagedObject.getNumber() + 1 == pagedObject.getTotalPages()} ? disabled"
class="page-item">
<a class="page-link"
th:href="@{''(size=${pagedObject.getSize()}, page=${pagedObject.getTotalPages()})}">&raquo;</a>
</li>
</ul>

<p class="text-muted small">
Showing page <span th:text="${pagedObject.getNumber() +1}"></span> of <span
th:text="${pagedObject.getTotalPages()}"></span>.
Total: <span th:text="${pagedObject.getTotalElements()}"></span>.

</p>
</div>


<div th:if="${pagedObject.getTotalElements() ==0}">
<div class="alert alert-warning" role="alert">
<span>No items available.</span>
</div>
</div>


</th:block>

Reference: https://github.com/gtiwari333/spring-boot-web-application-seed/blob/master/main-app/src/main/resources/templates/_fragments/_utils.html

No comments :

Post a Comment

Your Comment and Question will help to make this blog better...