pioto
pioto

Reputation: 2582

How can I elegantly preserve filter parameters when paginating with Thymeleaf?

On many of my pages, I have several options to sort or filter a long listing of results.

I'd like to have those selections preserved properly when someone pages through the data. For example:

  1. Start looking at the list of all tickets. (/tickets)
  2. Search for all tickets like "foo." (/tickets?query=foo)
  3. Go to the next page. (/tickets?query=foo&page=2)
  4. See the next page of tickets like "foo", not the 2nd page of "all tickets." (e.g. not /tickets?page=2)

In JSP, I came up with a solution like this:

<c:if test="${page.hasNext()}">
    <spring:url value="" var="nextLink">
        <c:forEach items="${param}" var="curParam">
            <c:if test="${curParam.key != 'page'}">
                <spring:param name="${curParam.key}" value="${curParam.value}"/>
            </c:if>
        </c:forEach>
        <spring:param name="page" value="${page.nextPageable().pageNumber}"/>
    </spring:url>
    <li>
        <a href="${nextLink}" aria-label="Next">
            <span aria-hidden="true">&raquo;</span>
        </a>
    </li>
</c:if>

That basically constructs a new URL pointing to the same path as the current page, but adds/replaces the "path" parameter to it's query parameters.

It's pretty ugly in JSP, but I don't see a way to really do this at all in Thymeleaf?

Or, perhaps there's some better way to do this using some Spring or Thymeleaf feature I haven't encountered yet?

My hope is to have a concise Thymeleaf fragment I can reuse everywhere I need pagination. So far, this is all I have, but it ends up missing missing the "query" parameter, etc. (I don't want to hard-code the query parameter here, because that would limit the reusability of this pagination code)

<li th:if="${page.hasNext()}">
    <a href="pagination.html" th:href="@{''(page=${page.nextPageable().pageNumber})}" aria-label="next">
        <span aria-hidden="true">&raquo;</span>
    </a>
</li>

Upvotes: 1

Views: 2598

Answers (2)

Alex Baico
Alex Baico

Reputation: 11

Maybe this will be usefull for someone using HTML and Spring with Thymeleaf.

In my case I use thymeleaf with spring. I have a DTO as a filter that is used in the controller to do the filtering.

public class Controller {
        private final int BUTTONS_TO_SHOW = 5;

        public String home(FilterDTO filterDTO @PageableDefault(size = 50) Pageable pageable, Model model){
          List<YourEntity> rows = YourEntityService.findAll();
          Pager pager = new Pager(rows.getTotalPages(), rows.getNumber(), BUTTONS_TO_SHOW);

          model.addAttribute("rows", rows);
          model.addAttribute("pager", pager);
          model.addAttribute("filterDTO", filterDTO);

          return "your-template";
        }
}

and the paginator like this:

<nav style="display: inline-block">
    <ul class="pagination">
      <li th:class="page-item" th:classappend="${rows.number == 0} ? ''">
        <a class="page-link" th:href="@{${#httpServletRequest.requestURI+'?'+filterDTO.toQueryString()}(page=0)}">&laquo;</a>
      </li>
      <li th:class="page-item" th:classappend="${rows.number == 0} ? ''">
        <a class="page-link" th:href="@{${#httpServletRequest.requestURI+'?'+filterDTO.toQueryString()}(page=${rows.number - 1})}">&larr;</a>
      </li>
      <li th:class="page-item" th:classappend="${rows.number == (page - 1)} ? 'active pointer-disabled'"
          th:each="page : ${#numbers.sequence(pager.startPage, pager.endPage)}">
        <a class="page-link" th:href="@{${#httpServletRequest.requestURI+'?'+filterDTO.toQueryString()}(page=${page - 1})}" th:if="${page != 0}"
           th:text="${page}"></a>
      </li>
      <li th:class="page-item" th:classappend="${rows.number + 1 == rows.totalPages or pager.endPage == 0} ? ''">
        <a class="page-link"
           th:href="@{${#httpServletRequest.requestURI+'?'+filterDTO.toQueryString()}(page=${rows.number + 1})}">&rarr;</a>
      </li>
      <li th:class="page-item" th:classappend="${rows.number + 1 == rows.totalPages or pager.endPage == 0} ? ''">
        <a class="page-link"
           th:href="@{${#httpServletRequest.requestURI+'?'+filterDTO.toQueryString()}(page=${rows.totalPages - 1})}">&raquo;</a>
      </li>
    </ul>
  </nav>

and in the FilterDTO class I implemented the method: toQueryString() that returns the query string with your applied filters.

Upvotes: 1

ndrone
ndrone

Reputation: 3582

Dandelion Datatables is project that can help you not reinvent the wheel. http://dandelion.github.io/components/datatables/

Upvotes: 0

Related Questions