Spring Thymeleaf prefill input with ZonedDateTime - spring

Today I am having some trouble with java.time and Thymeleaf
I have a form allowing users to edit an object. I have to prefill the form inputs with the current attributes of the object. This works in most cases. The only case that does not work is when i try to fill a date input with the value of a ZonedDateTime.
Here is the input:
<input type="date" class="form-control" th:field="*{startDate}">
and here is the attribute declaration:
private ZonedDateTime startDate;
Do you have any ideas why this does not work?

Related

Form input type DateTime using Thymeleaf + Spring MVC issue

I am struggling to use a Java LocalDateTime scheduledDateTime in a Thymeleaf form and getting it back to save it in the database. I get the following error message :
Bean property 'campaignExecution' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
It is really due to the datetime field. If I remove it from the html form everything works fine and I see the data from the object created in the controller.
My object contains the following along with the getter and setter returning thetype (LocalDateTime) :
#DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm")
private LocalDateTime scheduledDateTime;
My Controller initialize the value to now()
#RequestMapping({ "/campaign1"})
public String requestCampaign1(Model model) {
CampaignExecution ce = new CampaignExecution();
LocalDateTime localDateTime = LocalDateTime.now();
ce.setScheduledDateTime(localDateTime);
model.addAttribute("campaignExecution", ce);
And this is the form :
<form id="f" name="f" th:action="#{/campaign1}"
th:object="${campaignExecution}" method="post">
<div>
Schedule a date :
<input type="datetime-local" th:field=*{campaignExecution.scheduledDateTime} />
</div>
<hr>
<div>Parameters</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
Much easier than I was thinking. For th:field you cannot use multiple object but only the "form object". I was using the full qualifier : object name.property name.

Spring form with thymeleaf not binding right, throwing exception: Parameter is null

I have two views, one to book appointments and one to show them in a calendar view. After the booking was successful, there's a confirmation shown. The confirmation then forwards to the calendar view. I want to pass the booking infos as parameters to the calendar view so it can display the new booking accordingly in the calendar, but a null exception is thrown in that step.
I copied the template of a working form. I inspected the web request, all the necessary data is there, I think it's just not binding right.
data class EventAppointmentSearchRequest (val startDateTime: LocalDateTime, val endDateTime: LocalDateTime, val rooms: List<Room>)
/**
* Gets called when confirming a booking to add it to the DB.
*/
#PostMapping("/roomBookingConfirmation")
fun roomBookingConfirmation(model: Model, #ModelAttribute roomBookingRequest: RoomBookingRequest): String {
makeBooking(roomBookingRequest)
val date = roomBookingRequest.datetimeFrom
val start = roomBookingRequest.datetimeFrom.minusDays(date.dayOfWeek.value.toLong())
val end = roomBookingRequest.datetimeFrom.plusDays(7 - date.dayOfWeek.value.toLong())
model.addAttribute("eventAppointmentSearchRequest", EventAppointmentSearchRequest(
startDateTime = start,
endDateTime = end,
rooms = listOf(roomRepository.findByRoomName(roomBookingRequest.roomNr))
))
return "roomBookingConfirmation"
}
/**
* Displays the appointments in the calendar view according to the request
*/
#PostMapping("/calendarView")
fun calendarView(model: Model, #ModelAttribute eventAppointmentSearchRequest: EventAppointmentSearchRequest): String {
// THIS THROWS THE EXCEPTION: java.lang.IllegalArgumentException: Parameter specified as non-null is null: method ...requests.EventAppointmentSearchRequest.<init>, parameter startDateTime
...
}
<!-- /*#thymesVar id="eventAppointmentSearchRequest" type="de.tudarmstadt.pvw.tulpe.soonToBeArtifactory.requests.EventAppointmentSearchRequest"*/ -->
<form th:action="#{/calendarView}" method="post" th:object="${eventAppointmentSearchRequest}" id="forwardToCalendar" style="grid-column: span 4">
<H1 th:text="#{roomBooking.bookingConfirmed}">
Booking confirmed.
</H1>
<div class="links">
<a href="#" th:text="#{roomBooking.nowRedirecting}" onclick="forwardToCalendar()">Redirecting to
calendarView in </a> <b id="secondsLeft">7</b>
<input type="hidden" th:field="${eventAppointmentSearchRequest.startDateTime}" th:name="startDateTime" th:value="${eventAppointmentSearchRequest.startDateTime}">
<input type="hidden" th:field="${eventAppointmentSearchRequest.endDateTime}" th:name="endDateTime" th:value="${eventAppointmentSearchRequest.endDateTime}">
<input type="hidden" th:field="${eventAppointmentSearchRequest.rooms}" name="rooms[]" th:each="room: ${eventAppointmentSearchRequest.rooms}" th:value="${room.RoomId}">
</div>
...
</form>
I expect the form to just be bound correctly, I can see all the necessary data to use the constructor of EventAppointmentSearchRequest in the web inspector of my browser. Actual output is this error message:
java.lang.IllegalArgumentException: Parameter specified as non-null is null: method ...requests.EventAppointmentSearchRequest., parameter startDateTime
Something like this should suffice for the two date hidden inputs:
<input type="hidden" th:field="*{endDateTime}">
As for the third, th:field takes precedence over name and value attributes, if you look closely into the generated HTML, you'll see that the value is identical for each room hidden input, and it's the toString() on the list of Rooms. This is clearly wrong, and you need to specify each attribute of Room that you want to submit, have a look at the following article: https://www.baeldung.com/thymeleaf-list
I don't see the point in transmitting the details of the booking 2 more times between the client and server, I'd just pass a booking ID to the calendar page and have it load all the details...

Thymeleaf, Spring nested backing object is not binding the values on form submit

I have a nested object and I'm using it as a model for a form.
public AgeBracketSet implements Serializable{
private String id;
private List<AgeBracket> ageBrackets;
/* Getters and Setters */
}
I have successfully bound all the properties of this object to the form and I can visualize their values when the view state is rendered. Here's a simplified version of how I'm doing it with Thymeleaf. Essentially, I loop through the items of the list and get their attributes.
<form id="bracketForm" role="form" th:action="${flowExecutionUrl}" th:object="${ageBracketSet}" method="post">
<input th:id="'bracketSet_'+*{id}" th:field="*{id}" />
<th:block th:each="bracket,loop : *{ageBrackets}" th:id="'bracket_'+${bracket.id}">
<input th:id="'fromAge_'+${bracket.id}" th:field="*{ageBrackets[__${loop.index}__].fromAge}" />
<input th:id="'toAge_'+${bracket.id}" th:field="*{ageBrackets[__${loop.index}__].toAge}" />
</th:block>
</form>
However, when I make changes in the form and submit it, the model remains unchanged. I have confirmed this by debugging the service that receives the form data. The model does not have the changes made in the form. Am I doing anything wrong here?
I am embarrassed to say I've found the solution. The values simply weren't posted to the webflow for a lack of a 'name' attribute in each input. Using the same dynamically generated ID as a name did the job, and the bindings were correct for each item of the list. Like this:
<input th:id="'fromAge_'+${bracket.id}" th:name="'fromAge_'+${bracket.id}" th:field="*{ageBrackets[__${loop.index}__].fromAge}" />
Thanks to everyone who took the time to read this silly post. I'll be more careful next time ;)

Unwanted comma-splitting when binding string (from inputText) to List<String> in Spring

I'm working with Spring Web, my JSP has a inputText that I bind to List because I could set many inputText.
The problem is that if I have a inputText with something like "yyyyMMdd hh:mm:ss,SSS". I got a list with two elements: "yyyyMMdd hh:mm:ss" and "SSS", when I would like to get just one with all the text. Why?
This is the default behavior of how the binding in Spring works. if you have just one input, and have a value containing commas for that input, Spring will convert this into a list of values for that attribute.
Suppose you have:
<input type="hidden" name="fields" value="Hi, SO">
The mapping in the DTO for the attribute List<String> fields will be set to ["Hi", "SO"].
To overcome this, you can have an extra empty input for that field just before the ones containing the actual values.
<input type="hidden" name="fields" value="">
This will set the values in fields to ["", "Hi, SO"] and you can handle the empty string in your logic accordingly.

mvc how to use annotation with input tag

Hi I am using MVC 3 with Razor, I am using the below code.
I need to know whether I can use Annotations with this input tag?
<input type="text" id="#endDateName" name="#endDateName" value="#String.Format("{0:MM/dd/yyyy}", endDateValue)" />
I need annotation to check whether a proper date time value has been entered and not any random text.
Thanks in advance
After some help from Amyz,
I have used date picker now, and yes it does not allow characters like a,..z,!##, and so on.
But the problem is it does allow a date like say 02/1212312321/1231231313 this is what I want to prevent now the same can be seen on http://jqueryui.com/demos/datepicker/
Its better to handle this at client side only: for that you can use date picker:
Date Picker
or you can use data annotation like:
[DataType(DataType.Date, ErrorMessage = "Please enter a valid date (ex: 2/14/2011)")]
public DateTime DateTime { get; set; }
The final step is to register the adapter in our global.asax file:
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(DataTypeAttribute), typeof(DataTypeAttributeAdapter));

Resources