1. Introduction
In this article, we are going to present Thymeleaf Slider embedded in a Spring Boot application. In the presentation layer of sample application, we will use the Bootstrap framework for responsive design and bootstrap-slider for custom slider components.
Need more information about Thymeleaf and Spring Boot? check below links:
Thymeleaf Tutorial
Spring Boot with Thymeleaf
Forms in Thymeleaf
2. Maven dependencies
Project requires three common dependencies:
Maven pom.xml
file have the following structure:
Copy
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>thymeleaf-bootstrap-slider</artifactId>
<properties>
<bootstrap.version>4.0.0-2</bootstrap.version>
<webjars-locator.version>0.30</webjars-locator.version>
<lombok.version>1.18.2</lombok.version>
</properties>
<!-- Inherit defaults from Spring Boot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
</parent>
<!-- Add typical dependencies for a web application -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>${bootstrap.version}</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator</artifactId>
<version>${webjars-locator.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<!-- Package as an executable jar -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3. Model, Controller and Application class
The main purpose of this application is to save programming skills using sliders and Thymeleaf. The presentation layer contains single controller
- IndexController class that handles GET request to the root context and POST request with provided skills data.
The IndexController
have the following structure:
Copy
package com.frontbackend.thymeleaf.bootstrap.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.frontbackend.thymeleaf.bootstrap.model.ProgrammingSkills;
@Controller
@RequestMapping({ "/", "/index" })
public class IndexController {
@GetMapping
public String main(Model model) {
model.addAttribute("skills", new ProgrammingSkills());
return "index";
}
@PostMapping
public String save(ProgrammingSkills skills, Model model) {
model.addAttribute("skills", skills);
return "saved";
}
}
In the model layer we used a single POJO object that will store skills for several programming languages:
Copy
package com.frontbackend.thymeleaf.bootstrap.model;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Setter
@Getter
@NoArgsConstructor
public class ProgrammingSkills {
private int java;
private int css;
private int angular;
private int react;
private int python;
private int go;
}
This is our base object used in the Thymeleaf form (command object).
4. Template
The sample application comes with two HTML files.
The index.html
has the following structure:
Copy
<!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Spring Boot Thymeleaf Application - Bootstrap Slider</title>
<link th:rel="stylesheet" th:href="@{assets/bootstrap-slider/css/bootstrap-slider.css}"/>
<link th:rel="stylesheet" th:href="@{webjars/bootstrap/4.0.0-2/css/bootstrap.min.css} "/>
</head>
<body>
<!-- Navigation -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark static-top">
<div class="container">
<a class="navbar-brand" href="/">Thymeleaf - Bootstrap Slider</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive"
aria-controls="navbarResponsive"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home
<span class="sr-only">(current)</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">About</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Services</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Contact</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container">
<div class="row">
<div class="col">
<h2 class="mt-5">Programming skills</h2>
<form method="post" th:object="${skills}">
<div class="ml-2">
<div class="form-group mt-3">
<input id="java" type="text" th:field="*{java}" data-slider-min="1" data-slider-max="10"
data-slider-step="1"
data-slider-value="1" class="skill"/>
<span class="ml-2">JAVA: <strong id="javaVal">1</strong></span>
</div>
<div class="form-group mt-3">
<input id="css" type="text" th:field="*{css}" data-slider-min="1" data-slider-max="10"
data-slider-step="1"
data-slider-value="1" class="skill"/>
<span class="ml-2">CSS: <strong id="cssVal">1</strong></span>
</div>
<div class="form-group mt-3">
<input id="angular" type="text" th:field="*{angular}" data-slider-min="1" data-slider-max="10"
data-slider-step="1"
data-slider-value="1" class="skill"/>
<span class="ml-2">Angular: <strong id="angularVal">1</strong></span>
</div>
<div class="form-group mt-3">
<input id="python" type="text" th:field="*{python}" data-slider-min="1" data-slider-max="10"
data-slider-step="1"
data-slider-value="1" class="skill"/>
<span class="ml-2">Python: <strong id="pythonVal">1</strong></span>
</div>
<div class="form-group mt-3">
<input id="react" type="text" th:field="*{react}" data-slider-min="1" data-slider-max="10"
data-slider-step="1"
data-slider-value="1" class="skill"/>
<span class="ml-2">React: <strong id="reactVal">1</strong></span>
</div>
<div class="form-group mt-3">
<input id="go" type="text" th:field="*{go}" data-slider-min="1" data-slider-max="10"
data-slider-step="1"
data-slider-value="1" class="skill"/>
<span class="ml-2">Go: <strong id="goVal">1</strong></span>
</div>
</div>
<button class="btn btn-primary" type="submit">Submit form</button>
</form>
</div>
</div>
</div>
<script th:src="@{/webjars/jquery/jquery.min.js}"></script>
<script th:src="@{/webjars/popper.js/umd/popper.min.js}"></script>
<script th:src="@{/webjars/bootstrap/js/bootstrap.min.js}"></script>
<script th:rel="stylesheet" th:src="@{assets/bootstrap-slider/bootstrap-slider.js}"></script>
<script>
$(".skill").slider();
$(".skill").on("slide", function (slideEvt) {
$("#" + slideEvt.target.id + "Val").text(slideEvt.value);
});
$(".skill").on("change", function (slideEvt) {
$("#" + slideEvt.target.id + "Val").text(slideEvt.value.newValue);
});
</script>
</body>
</html>
We used external library for making custom sliders - bootstrap-slider . This template present sliders which we can use to enter our skills level from 1 to 10.
The saved.html
presents salected values:
Copy
<!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Spring Boot Thymeleaf Application - Bootstrap Slider</title>
<link th:rel="stylesheet" th:href="@{webjars/bootstrap/4.0.0-2/css/bootstrap.min.css} "/>
</head>
<body>
<!-- Navigation -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark static-top">
<div class="container">
<a class="navbar-brand" href="/">Thymeleaf - Bootstrap Slider</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home
<span class="sr-only">(current)</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">About</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Services</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Contact</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container">
<h2 class="mt-5">Programming skills</h2>
<p>JAVA: <strong th:text="${skills.java}"></strong></p>
<p>CSS: <strong th:text="${skills.css}"></strong></p>
<p>Angular: <strong th:text="${skills.angular}"></strong></p>
<p>Python: <strong th:text="${skills.python}"></strong></p>
<p>React: <strong th:text="${skills.react}"></strong></p>
<p>Go: <strong th:text="${skills.go}"></strong></p>
<a th:href="@{/}" class="btn btn-primary">Go back</a>
</div>
</body>
</html>
5. The output
Started application is available under http://locahost:8080
URL and presents the following functionality:
6. Conclusion
In this article, we presented how to create Thymeleaf Slider in a Spring Boot application. Sliders are components used very often in an HTML form, especially on mobile devices. That kind of component gives users a great experience - it is easier to move the slider than enter the value from the keyboard.
{{ 'Comments (%count%)' | trans {count:count} }}
{{ 'Comments are closed.' | trans }}