1. Introduction
In this article, we are going to present a custom Thymeleaf Time Picker embedded in a Spring Boot application. We use a custom Time Picker component to enter time on the Thymeleaf form. The provided value will be submitted to the backend and presented on another page.
For more information about Thymeleaf go and check below links:
Thymeleaf related articles organized in several categories
How to configure Thymeleaf with Spring Boot
Using Forms in Thymeleaf
2. Dependencies
2.1. Maven dependencies
Project was built using three common Maven dependencies:
2.2. Front-End libraries
Presentation layer use several libraries and frontend frameworks:
bootstrap - framework for building responsive websites,
moment - javascript library for time/date management,
bootstrap-datetimepicker - custom time picker component,
jquery - required by bootstrap.
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-timepicker</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 sample application presented in this article will use Thymeleaf form to submit information about Event
like Title
, Description
and Time
. The time of the event will be selected using a custom Time Picker component.
We have one controller
- IndexController class that handles GET request to the root context and POST request with provided form 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.Event;
@Controller
@RequestMapping({ "/", "/index" })
public class IndexController {
@GetMapping
public String main(Model model) {
model.addAttribute("event", new Event());
return "index";
}
@PostMapping
public String save(Event event, Model model) {
model.addAttribute("event", event);
return "saved";
}
}
The model layer contains a single object Event
with the following structure:
Copy
package com.frontbackend.thymeleaf.bootstrap.model;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
public class Event {
private String title;
private String description;
private String time;
}
The Event
object is our base object used in the Thymeleaf form (command object).
Spring Boot main class that starts the server has the following structure:
Copy
package com.frontbackend.thymeleaf.bootstrap;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4. Template
We created two Thymeleaf templates:
index.html - contains Thymeleaf form with Time Picker component,
saved.html - will present submitted data from the previous view.
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 Time Picker</title>
<link th:rel="stylesheet" th:href="@{assets/bootstrap-datetimepicker/css/bootstrap-datetimepicker.css}"/>
<link th:rel="stylesheet" th:href="@{webjars/bootstrap/4.0.0-2/css/bootstrap.min.css} "/>
<link rel="stylesheet" href="https://netdna.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.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 Time Picker</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-md-4 mt-5">
<form method="post" th:object="${event}">
<div class="form-group">
<label for="title">Title:</label>
<input type="text" id="title" placeholder="Title" class="form-control" th:field="*{title}"/>
</div>
<div class="form-group">
<label for="description">Description:</label>
<textarea type="text" rows="2" id="description" placeholder="Description" class="form-control"
th:field="*{description}"></textarea>
</div>
<div class="form-group">
<label for="time">Time:</label>
<div class="input-group date" id="event_time">
<input type="text" id="time" value="11:31:00" placeholder="Time" class="form-control" th:field="*{time}"/>
<div class="input-group-addon input-group-append">
<div class="input-group-text">
<i class="fa fa-clock-o"></i>
</div>
</div>
</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:src="@{assets/moment/moment.min.js}"></script>
<script th:src="@{assets/bootstrap-datetimepicker/js/bootstrap-datetimepicker.min.js}"></script>
<script>
$('#event_time').datetimepicker({
"allowInputToggle": true,
"showClose": true,
"showClear": true,
"showTodayButton": true,
"format": "HH:mm:ss",
});
</script>
</body>
</html>
To create Time Picker we use bootstrap-datetimepicker library available under GitHub Repository - https://github.com/monim67/bootstrap-datetimepicker/ . With this library we can also create complex time/date picker components.
The saved.html
view presents submitted data:
Copy
<!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Spring Boot Thymeleaf Application - Bootstrap Time Picker</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 Time Picker</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 mb-4">Event submitted</h2>
<p><label>Title: </label> <strong th:text="${event.title}"></strong></p>
<p><label>Description: </label> <strong th:text="${event.description}"></strong></p>
<p><label>Time: </label> <strong th:text="${event.time}"></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 build a form with Thymeleaf Time Picker component in a Spring Boot application. We used component that can be easily operated on mobile devices.
As usual the code used in this article is available under our GitHub repository .
{{ 'Comments (%count%)' | trans {count:count} }}
{{ 'Comments are closed.' | trans }}