I have a simple snippet of form like:
<form th:action="@{'/save'}" th:object="${account}" method="post">
<div class="form-group">
<label for="expirationDate">Expiration date</label>
<input type="datetime-local" class="form-control" id="expirationDate"
placeholder="Expiration date" th:field="*{expirationTime}"/>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
I'm passing there a filled object account
and expirationTime
is a LocalDateTime
field. The problem is that the expirationTime
is not bind with the value passed to the form (object which is passed is 100% correct).
Any idea why?
Let's look at how to use a date-picker to submit a Date value from a Thymeleaf form. The @DateTimeFormat annotation declares that the birthDate field should be formatted as a Date. When we submit the form, a controller will intercept the Student object mapped in the form with th:object attribute.
The <input type="date"> defines a date picker. The resulting value includes the year, month, and day. Tip: Always add the <label> tag for best accessibility practices!
Thymeleaf is a server-side Java-based template engine for both web and standalone environments, capable of processing HTML, XML, JavaScript, CSS and even plain text. It is more powerful than JPS and responsible for dynamic content rendering on UI.
Edit: Simply put, Spring/Thymeleaf doesn't format a Java 8 date correctly for the datetime-local input type. Tell Spring how to format the value correctly with @DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm").
The annotation @DateTimeFormat tells Thymeleaf how to format the date string when parsing/formatting. That includes producing the value= annotation in the HTML input, and reading in POST data submitted by the form. The datetime-local input type expects a value formatted yyyy-MM-dd'T'HH:mm, so we use that as the formatter in the model class.
public class DateContainer {
private String name;
@DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm")
private LocalDateTime dateTime;
public LocalDateTime getDateTime() {
return dateTime;
}
public void setDateTime(LocalDateTime dateTime) {
this.dateTime = dateTime;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@RequestMapping("/dateTest")
public String dateTest(final DateContainer dateContainer) {
if (dateContainer.getDateTime() == null) {
dateContainer.setDateTime(LocalDateTime.now());
}
return "dateTest";
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org/">
<head></head>
<body>
<h1>Hello World!</h1>
<form th:action="@{/dateTest}" th:object="${dateContainer}">
<label>Name: </label><input type="text" th:field="*{name}"/>
<label>Date Time: </label><input type="datetime-local" th:field="*{dateTime}"/>
<input type="submit" value="Submit"/>
</form>
</body>
</html>
<!DOCTYPE html>
<html>
<head></head>
<body>
<h1>Hello World!</h1>
<form action="/dateTest">
<label>Name: </label><input type="text" id="name" name="name" value="" />
<label>Date Time: </label><input type="datetime-local" id="dateTime" name="dateTime" value="2017-08-28T13:01" />
<input type="submit" value="Submit" />
<input type="hidden" name="_csrf" value="437b30dc-a103-44d0-b4e9-791d8de62986" /></form>
</body>
</html>
Screenshot in Chrome 60
The datetime-local input type is a new HTML5 type and isn't supported in all browsers. See compatibility: https://caniuse.com/#search=datetime-local
In non-compliant browsers, the datetime-local field will simply appear as a text field, and will contain the date and time with the T in between. That may lead to usability issues depending on your use case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With