Skip to content

jpenren/thymeleaf-spring-data-dialect

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Thymeleaf Spring Data Dialect

Data pagination made easy with thymeleaf and spring data.

This is a dialect for Thymeleaf that provides some attributes to create pagination and sorting elements, bootstrap style, based on Spring Data.

Usage

Maven dependency:

<dependency>
	<groupId>io.github.jpenren</groupId>
	<artifactId>thymeleaf-spring-data-dialect</artifactId>
	<version>3.6.0</version>
</dependency>

Add the Spring Data dialect to your existing Thymeleaf template engine:

templateEngine.addDialect(new SpringDataDialect());		// This line adds the dialect to Thymeleaf

If using Spring Boot you can add the following line and the ThymeleafAutoConfiguration class will add the dialect to the template engine.

    @Bean
    public SpringDataDialect springDataDialect() {
        return new SpringDataDialect();
    }

This will introduce the sd namespace, and the new attribute processors that you to use in your pages: pagination, pagination-sort, pagination-summary, pagination-url, page-object, pagination-qualifier and page-size-selector.

Examples

In your @Controller

@RequestMapping("/users")
public String list(ModelMap model, @SortDefault("username") Pageable pageable){
	model.addAttribute("page", userService.find(pageable));
	
	return "users/list";
}

Your html page looks like:

<table class="table table-striped table-hover">
	<thead>
		<tr>
		  <th><a class="sorted" sd:pagination-sort="username" >Username</a></th>
		  <th><a class="sorted" sd:pagination-sort="firstName" >First name</a></th>
		  <th>Last Name</th>
		  <th></th>
		</tr>
	</thead>
	<tbody>
		<tr th:each="row : ${page}">
		  <th scope="row" th:text="${row.username}">Username</th>
		  <td th:text="${row.firstName}">Name</td>
		  <td th:text="${row.lastName}">Last Name</td>
		  <td><a href="#">edit</a></td>
		</tr>
	</tbody>
</table>

<div class="row">
    <div class="col-sm-6">
    	<div sd:pagination-summary="">info</div>
    </div>
    <div class="col-sm-6">
    	<nav class="pull-right">
		<ul class="pagination" sd:pagination-split="7" sd:pagination="full">
			<!-- Pagination created by SpringDataDialect, this content is just for mockup -->
			<li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>
		   	<li class="active"><a href="#">1 <span class="sr-only">(current)</span></a></li>
		</ul>
	</nav>
    </div>
</div>

Use optional attribute sd:pagination-split to configure the number of links to show.

alt text

Pagination with pager:

<nav>
    <ul class="pagination" sd:pagination="pager">
        <!-- Pagination created by SpringDataDialect, this content is just for mockup -->
        <li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>
        <li class="active"><a href="#">1 <span class="sr-only">(current)</span></a></li>
    </ul>
</nav>

alt text

Aligned links:

<nav>
    <ul class="pagination" sd:pagination="aligned-links">
        <!-- Pagination created by SpringDataDialect, this content is just for mockup -->
        <li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>
        <li class="active"><a href="#">1 <span class="sr-only">(current)</span></a></li>
    </ul>
</nav>

alt text

Compact pager:

<div>
    <span sd:pagination-summary="compact">info</span>
    <div class="btn-group pager-compact" sd:pagination="compact-pager">
        <!-- Pagination created by SpringDataDialect, this content is just for mockup -->
        <a href="#" class="btn btn-default disabled"><span class="glyphicon glyphicon-chevron-left"></span></a>
        <a href="#" class="btn btn-default"><span class="glyphicon glyphicon-chevron-right"></span></a>
    </div>
</div>

alt text

Page size selector (default requires your own javascript code, no action associated):

Show <span sd:page-size-selector="default"></span> entries

alt text

Page size selector (with javascript code implemented):

Show <span sd:page-size-selector="javascript"></span> entries

alt text

Page size selector (dropdown):

<div class="btn-group dropup" sd:page-size-selector="dropdown"></div>

alt text

Multiple tables on the same page:

On your @Controller

@RequestMapping("/users")
public String list(ModelMap model, @Qualifier("foo") Pageable first, @Qualifier("bar") Pageable second){
	model.addAttribute("page", userService.find(first));
	model.addAttribute("barPage", userService.find(second));
	
	return "users/list";
}
<div class="row">
	<div class="col-md-6" sd:page-object="${page}" sd:pagination-qualifier="foo">
		<div class="panel panel-default">
		<div class="panel-body">
			<table class="table table-striped table-hover">
				<thead>
				    <tr>
				      <th><a class="sorted" sd:pagination-sort="username" >Username</a></th>
				      <th><a class="sorted" sd:pagination-sort="firstName" >First name</a></th>
				    </tr>
			    </thead>
			    <tbody>
				    <tr th:each="row : ${page}">
				      <td th:text="${row.username}">First Name</td>
				      <td th:text="${row.firstName}">Last Name</td>
				    </tr>
			    </tbody>
			</table>
			
	    	<nav>
	            <ul class="pagination" sd:pagination="full">
	                <!-- Pagination created by SpringDataDialect, this content is just for mockup -->
	                <li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>
	                <li class="active"><a href="#">1 <span class="sr-only">(current)</span></a></li>
	            </ul>
	        </nav>
	    </div>
        </div>
	</div>
	<div class="col-md-6" sd:page-object="${barPage}" sd:pagination-qualifier="bar">
		<div class="panel panel-default">
		<div class="panel-body">
			<table class="table table-striped table-hover">
				<thead>
				    <tr>
				      <th><a class="sorted" sd:pagination-sort="username" >Username</a></th>
				      <th><a class="sorted" sd:pagination-sort="firstName" >First name</a></th>
				    </tr>
			    </thead>
			    <tbody>
				    <tr th:each="row : ${barPage}">
				      <td th:text="${row.username}">First Name</td>
				      <td th:text="${row.firstName}">Last Name</td>
				    </tr>
			    </tbody>
			</table>
			
			<nav class="">
	            <ul class="pagination" sd:pagination="full">
	                <!-- Pagination created by SpringDataDialect, this content is just for mockup -->
	                <li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>
	                <li class="active"><a href="#">1 <span class="sr-only">(current)</span></a></li>
	            </ul>
	        </nav>
	    </div>
        </div>
	</div>
</div>

alt text

By default SpringDataDialect search in the request for the attribute "page" or if one attribute of type org.springframework.data.domain.Page<?> exists. To use another model attribute, use sd:page-object="${attrName}"

To specify the pagination url use sd:pagination-url tag:

<nav>
    <ul class="pagination" sd:pagination="pager" sd:pagination-url="@{/some-url}">
        <!-- Pagination created by SpringDataDialect, this content is just for mockup -->
        <li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>
        <li class="active"><a href="#">1 <span class="sr-only">(current)</span></a></li>
    </ul>
</nav>

Sort Icons

The generated HTML has the CSS classes sorted, sorted-asc and sorted-desc. This allows you to quite easily add some custom CSS to have sort icons in the table headers.

Example with FontAwesome:

table.table thead .sorted:after{
	display: inline-block;
	font-family: 'FontAwesome';
	opacity: 0.8;
	margin-left: 1em;
}
table.table thead .sorted.sorted-desc:after{
	content: "\f15e";
}
table.table thead .sorted.sorted-asc:after{
	content: "\f15d";
}

Example with Unicode characters:

.sorted-desc::after, .sorted-asc::after {
    float: right;
}

.sorted-desc::after{
    content:"\25BC";
}

.sorted-asc::after{
    content: "\25B2";
}