1. Introduction
In this article, we are going to present Thymeleaf Country Picker component. It allows you to present country names with flags in select inputs.
You can find more information about Thymeleaf and Forms in the following links:
Thymeleaf Posts
Creating forms in Thymeleaf
2. Dependencies
2.1. Maven dependencies
Country Picker component will be placed in a Spring Boot application created as a Maven project using three main dependencies:
- org.springframework.boot:spring-boot-starter-web:2.1.5.RELEASE - Spring Boot Web dependency,
- org.springframework.boot:spring-boot-starter-thymeleaf:2.1.5.RELEASE - Thymeleaf template engine dependency,
- org.projectlombok:lombok:1.18.2 - library for generating common methods for POJO objects,
- org.webjars:bootstrap:4.0.0-2 - webjar with Bootstrap framework.
2.2. Front-End libraries
- bootstrap - a frontend framework for creating responsive websites.
- bootstrap-select-country - JS library for creating country picker component.
Maven pom.xml
file have the following structure:
<?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-country-picker</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 Main Application class
The model layer contains a single class Address
with a field country
that will hold a country code of the submitted country:
package com.frontbackend.thymeleaf.bootstrap.model;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Setter
@Getter
@NoArgsConstructor
public class Address {
private String country;
}
GET and POST requests are handle by IndexController
class that is a Spring Boot Web Controller:
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.Address;
@Controller
@RequestMapping({ "/", "/index" })
public class IndexController {
@GetMapping
public String main(Model model) {
model.addAttribute("address", new Address());
return "index";
}
@PostMapping
public String save(Address address, Model model) {
model.addAttribute("address", address);
return "saved";
}
}
The Application
is the Java class with the main method that starts the Spring Boot application server:
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. Templates
The presentation layer contains two Thymeleaf templates:
- index.html - on this view user can select country from country picker,
- saved.html - this template will display submitted value from the previous view.
The index.html
template has the following structure:
<!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Spring Boot Thymeleaf Application - Bootstrap Country Picker</title>
<link th:rel="stylesheet" th:href="@{/webjars/bootstrap/4.0.0-2/css/bootstrap.min.css} "/>
<link th:rel="stylesheet" th:href="@{/assets/bootstrap-select/css/bootstrap-select.min.css} "/>
<link th:rel="stylesheet" th:href="@{/assets/bootstrap-select-country/css/bootstrap-select-country.min.css} "/>
<link th:rel="stylesheet" th:href="@{/assets/bootstrap-select-country/css/bootstrap4-support.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 Country 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-lg-5 mt-5">
<form method="post" th:object="${address}">
<div class="form-group">
<label for="country">Select country</label>
<select class="form-control selectpicker countrypicker" id="country" th:field="*{country}"
data-flag="true">
</select>
</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/bootstrap-select/js/bootstrap-select.min.js}"></script>
<script th:src="@{/assets/bootstrap-select-country/js/bootstrap-select-country.min.js}"></script>
<script>
$('.countrypicker').countrypicker();
</script>
</body>
</html>
We used external JavaScript plugin for creating responsive Country Picker components: https://github.com/mojoaxel/bootstrap-select-country.
To initialize bootstrap-select-country library we use the following code:
$('.countrypicker').countrypicker();
The saved.html
template has the following structure:
<!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Spring Boot Thymeleaf Application - Bootstrap Country 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 Country 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="mt-5">Country: <strong th:text="${address.country}"></strong></div>
<a th:href="@{/}" class="btn btn-primary mt-5">Go back</a>
</div>
</body>
</html>
5. The output
The running application is available under http://locahost:8080
URL and presents the following functionality:
6. Conclusion
In this article, we presented Thymeleaf Country Picker component. This component should be useful for forms where users provide their address data. It is fully responsive and works with the Bootstrap framework.
As usual, the code used in this article is available under our GitHub repository.
{{ 'Comments (%count%)' | trans {count:count} }}
{{ 'Comments are closed.' | trans }}