Query params
Thymeleaf source
<form action="/people" method="get"> <sl:label for="query-params-q">Search people</sl:label> <sl:input type="search" id="query-params-q" name="q" th:value="${param.q}" placeholder="Name or email"/> <sl:query-params except="q"/></form>Rendered HTML
<form action="/people" method="get"> <label class="label" for="query-params-q">Search people</label> <input class="input" type="search" id="query-params-q" name="q" value="ada" placeholder="Name or email"> <input type="hidden" name="sort" value="email,desc"> <input type="hidden" name="size" value="50"></form>Searching a sorted table
Section titled “Searching a sorted table”A search above a table is a GET form: sending it asks for the same page with ?q=..., which the
controller filters on. A browser sends only the form’s own fields, so on its own the form would forget the table’s
order and page size. <sl:query-params> copies the current request’s other parameters into the form as hidden inputs:
<form th:action="@{/people}" method="get" role="search"> <sl:input type="search" name="q" th:value="${param.q}" aria-label="Search people"/> <sl:query-params except="q"/></form>In a request for /people?q=ada&sort=email,desc&size=50&page=2, that renders:
<form action="/people" method="get" role="search"> <input class="input" type="search" name="q" value="ada" aria-label="Search people"> <input type="hidden" name="sort" value="email,desc"> <input type="hidden" name="size" value="50"></form>and searching for “grace” asks for /people?q=grace&sort=email,desc&size=50.
exceptnames the form’s own fields, separated by commas (except="q,status"). Without it,qwould be sent twice: the field’s new value and the hidden copy of the old one.- The page number is always left out, so a new search starts on the first page. It is the page parameter your
Pageablereads (spring.data.web.pageable.*, see parameter names); withqualifier="members"it ismembers_page, for the second table on a page. - A repeated parameter stays repeated, in its order:
?sort=name,desc&sort=emailgives twosortinputs, as Spring Data’sSortreads them. - Values are decoded once (
?q=ada%20l%C3%A9givesvalue="ada lé") and escaped like any other attribute value, so a parameter cannot add markup.
The controller needs nothing for it: the Pageable reads sort and size as it does for the table’s links.
@GetMapping("/people")String people(@RequestParam(required = false) String q, @PageableDefault(sort = "name") Pageable pageable, Model model) { Page<Person> people = q == null || q.isBlank() ? personRepository.findAll(pageable) : personRepository.findByNameContainingIgnoreCaseOrEmailContainingIgnoreCase(q, q, pageable); model.addAttribute("people", people); return "people";}The links of the table’s headers, its pagination and the rows-per-page menu keep q in the same
way, as they are built from the request too.
Outside the form
Section titled “Outside the form”Other attributes go to every hidden input. With form, the inputs belong to a form elsewhere on the page. The
live search with htmx uses this to put them next to the table, so they are swapped with it
and follow the order of the table they came with:
<form id="people-search" ...>...</form><div id="people-results"> <sl:query-params except="q" form="people-search"/> <sl:table th:page="${people}">...</sl:table></div>Attributes
Section titled “Attributes”| Attribute | Values | Default | Description |
|---|---|---|---|
except | string | — | The parameters not to copy, separated by commas: the fields the form has itself (q, q,status). |
qualifier | string | — | The @Qualifier of the controller's Pageable, for a second table on the page: its page parameter (members_page) is the one left out. |
Every prop can also be set from an expression: th:except="${...}". Any other attribute passes through to the rendered element, and class is appended.