Form Select and Thymeleaf - spring

I'm porting my app to Thymeleaf and i'm having problems in creating form select from List of Objects.
I have this form
<form th:with="reservationUrl=(${price != null} ? '/book/confirm' : '/book/new')"
th:action="#{${reservationUrl}}" method="POST"
class="form-signin" th:object="${reservation}"
id="form-signin">
<div class="form-group row">
<label class="col-sm-2 col-form-label" for="plate"
th:text="#{reservation.plate }">Targa</label>
<div class="col-sm-4 input-group">
<select th:type="*{plate}" class="form-control">
<option th:each="p : ${plates}"
th:value="${p.plateId}" th:text="${p.plateNumber}">Opzione</option>
</select>
</div>
// rest of the form
From the controller I have a List<Plate> plates and my Reservation has a Plate field, so it's a really basic select association (which worked with plain JSP)
I'm getting this exception
Exception evaluating SpringEL expression: "p.plateId" (reservation:67)] with root cause
Property or field 'plateId' cannot be found on object of type 'org.thymeleaf.util.EvaluationUtil$MapEntry' - maybe not public?
This is Plate
#Entity
public class Plate {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long plateId;
private String plateNumber;
private String plateName;
#ManyToOne
#JoinColumn(name="userId")
#JsonBackReference(value="plates-user-reference")
private User user;
private boolean favourite;
#JsonIgnore
private boolean enabled;
//standard getters and setters

EXAMPLE
<div class="form-group">
<label for="location">Pick a location:</label>
<select class="form-control" th:value="${appointment.location}" name="location" id="location"
>
<option disabled="disabled" selected="selected" > -- select the location --</option>
<option>Boston</option>
<option>New York</option>
<option>Chicago</option>
<option>San Francisco</option>
</select>
</div>
if you want to try a drop-down menu then yu can follow this way.

Related

how to bind list of object for sending post request in spring boot and thymeleaf

I have a booking entity and another entity is guest. the relation between them onetomany.
booking entity:
#Entity
public class Booking {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String nameInit;
private String firstName;
private String lastName;
private String email;
private String numberInit;
private String number;
private boolean status;
#JsonIgnore
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<Guest>guests;
Guest entity:
#Entity
public class Guest{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String nameInit;
private String name;
private String age;
private String gender;
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "booking_id")
private Booking booking;
thymeleaf form:
<div class="guest-inputs-wrapper" th:each="item, stat : *{guests}">
<div class="row">
<div class="col-md-1">
<div class="input-field col s12">
<div class="guest-number">
Guest <span class="number">1</span>
</div>
</div>
</div>
<div class="col-md-2">
<div class="input-field col s12">
<select name="nameInit" th:field="*{guests[__${stat.index}__].nameInit}" id="g-title-1">
<option value="" disabled selected>Title</option>
<option value="1">Mr.</option>
<option value="2">Mrs.</option>
<option value="3">Ms.</option>
</select>
</div>
</div>
<div class="col-md-4">
<div class="input-field col s12">
<input type="text" class="validate" name="name" th:field="*{guests[__${stat.index}__].name}" id="g-fullname-1" required>
<label>Full Name</label>
</div>
</div>
<div class="col-md-1">
<div class="input-field col s12">
<input type="text" class="validate" name="age" th:field="*{guests[__${stat.index}__].age}" id="g-age-1" required>
<label>Age</label>
</div>
</div>
<div class="col-md-3">
<div class="input-field col s12">
<div class="custom-radio">
<input type="radio" id="m-gender-1" name="gender" th:field="*{guests[__${stat.index}__].gender}" value="Male" checked>
<label for="m-gender-1">Male</label>
</div>
<div class="custom-radio">
<input type="radio" id="f-gender-1" name="gender" th:field="*{guests[__${stat.index}__].gender}" Value="Female">
<label for="f-gender-1">Female</label>
</div>
</div>
</div>
Controller:
#GetMapping("/booking/room/{roomId}")
public String bookingPage(Model model, #PathVariable Long roomId, HttpSession session){
Booking booking = new Booking();
booking.getGuests().add(new Guest());
model.addAttribute("booking", booking);
return "web/cart";
}
#PostMapping("/room/save-booking")
public String createBooking(Model model,#Valid Booking booking, BindingResult result, HttpSession session){
if (result.hasErrors()){
model.addAttribute("error", true);
return null;
}
hotelBookingService.save(booking);
guestService.saveAll(booking.getGuests());
model.addAttribute("success", true);
return "redirect:/main";
}
after submitting only one guest information is saved in db with booking information. but i want a list of guest. where is my worng i can't find. why form do not pass list of guest ? please help
For starters, within your th:each loop you have element ids with are not unique and don't use the stat index, for example g-title-1.
Secondly, the same goes for the name on each input. The th:each loop is an abstraction for document generation. As far as the browser is concerned, there is no "list" associated with the loop. What does that mean? When it comes time to submit, you will have a bunch of duplicate names as well, which will cause problems.
You could refactor your code/script to save one guest to a booking at a time, or you could use javascript to build a FormData object that grabs data from the inputs and keeps the lists like you want. I'm sure there are other solutions as well.

Spring How to update database entites from dropdown lists thymeleaf

So I need to update the entities in my table with the selected values from dropdown lists from thymeleaf.
What I want to do is update the movie column based on the selections from dropdown list. But I have more than one dropdown list for each WeekMovie entity.
I cant figure out how to update them all.
My WeekMovies Class
#Entity
public class WeekMovies {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#ManyToOne
#JoinColumn(name="movie_id")
private Movie movie;
#ManyToOne
#JoinColumn(name="saloon_id")
private Saloon saloon;
//getter setters.
My Controller
#RequestMapping(value = "/update",method= RequestMethod.GET)
public String updateweekmovies(Model model){
List<WeekMovies> weekMoviesList = weekMovieService.findAll();
List<Movie> movieList= movieService.findAll();
model.addAttribute("weekMovieList",weekMoviesList);
model.addAttribute("movieList",movieList);
return "updateweekmovies";
}
#RequestMapping(value = "/update",method= RequestMethod.POST)
public String updateweekPost(Model model){
return "updateweekmovies";
}
My Thymeleaf
div class="container">
<div class="row">
<form class="form-horizontal" th:action="#{/week/update}" method="post"
enctype="multipart/form-data">
<fieldset>
<legend class="center-block">
Update Book Information<span style="font-size: small"> * is a
required field</span>
</legend>
<!-- category -->
<div class="form-group">
<label class="col-md-2 control-label" for="weekmovie">*
Category</label>
<div class="col-md-8">
<li th:each="weekmovie:${weekMovieList}">
<select th:value="${weekmovie.movie}" id="weekmovie" name="weekmovie" class="form-control">
<option value="" selected="selected" disabled="disabled">Please
select an option...</option>
<option th:each="movie:${movieList}" th:value="${movie.id}" th:text="${movie.title}"> </option>
</select>
</li>
</div>
</div>
<div class="form-group">
<div class="col-md-2"></div>
<div class="col-md-8">
<button type="submit" class="btn btn-success">Update Movie</button>
</div>
</div>
</fieldset>
</form>
</div>

How to assign entity to another entity in a form using ThymeLeaf?

I am working on MVC Java project and am using Spring Boot with ThymeLeaf. The issue I have is, that when creating a Task, I want to select and save a User, that will be assign to the task. I managed to do the selection correctly, but am unable to save the selected user. It always saves without the User assigned.
Here is my Task entity class:
#Entity
public class Task extends BaseEntity {
private String name;
private String description;
private Date dateOfCreation;
#DateTimeFormat(pattern = "yyyy-MM-dd")
private Date dueDate;
#ManyToOne
private User assignee;
public Task() {
this.dateOfCreation = new Date(System.currentTimeMillis());
}
}
My User entity is as follows:
#Entity
public class User extends BaseEntity {
private String username;
private String password;
#OneToMany(mappedBy = "assignee")
private List<Task> assignedTasks;
}
Where BaseEntity contains
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Version
private Integer version;
My controller function, that is responsible for my taskform.html is:
#RequestMapping("/new")
public String newTask(Model model){
model.addAttribute("task", new Task());
model.addAttribute("users", userService.getAllUsers());
return "task/taskform";
}
And my taskform.html looks like this:
<form class="form-horizontal" th:object="${task}" th:action="#{/task}" method="post">
<input type="hidden" th:field="*{id}"/>
<input type="hidden" th:field="*{version}"/>
<div class="form-group">
<label class="col-sm-2 control-label">Name:</label>
<div class="col-sm-10">
<input type="text" class="form-control" th:field="*{name}"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Description:</label>
<div class="col-sm-10">
<input type="text" class="form-control" th:field="*{description}"/>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Description:</label>
<div class="col-sm-10">
<input type="date" th:value="*{dueDate}" th:field="*{dueDate}" id="dueDate" />
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">Select user:</label>
<div class="col-sm-10">
<select class="form-control">
<option th:field="*{assignee}" th:each="assignee : ${users}" th:value="${assignee}" th:text="${assignee.username}">
</option>
</select>
</div>
</div>
<div class="row">
<button type="submit" class="btn btn-default">Submit</button>
</div>
I am trying to pass the object from users list as the value, but it does not work Any idea, how to do it?
Showing the users works as expected:
Working frontend
Null is being assigned to assignee column, where the user should be assigned.
Null in H2 Database
EDIT
Here is my POST method from Task Controller:
#RequestMapping(method = RequestMethod.POST)
public String saveOrUpdate(Task task){
taskService.persistTask(task);
return "redirect:/task/list";
}

Spring Nested object is getting null while submitting form

I am trying to post data with thymeleaf, command model has two nested objects, one is fetching data, while another is fetching null. I am confused, what is going on behind the scene, though using the same concept and code.
Please notice, I am getting data for People Object in logs, but not for Project Object, though using the same code. Please help.
Form Snippet.
<form th:fragment="form" method="post" th:object="${expense}" th:action="#{/createexpense}">
<input type="hidden" th:field="*{expenseId}" />
<div class="form-group">
<label class="col-md-4 control-label" for="textarea">Expense Description</label>
<div class="col-md-4">
<textarea class="form-control" id="textarea" th:field="*{description}" name="textarea">Expense Description</textarea>
</div>
</div>
<div class="form-group">
<label class="col-md-4 control-label" for="textinput">Amount</label>
<div class="col-md-4">
<input id="textinput" name="textinput" type="text" placeholder="Enter Amount" th:field="*{amount}" class="form-control input-md">
</div>
</div>
<div class="form-group">
<label class="col-md-4 control-label" for="textinput">Project</label>
<div class="col-md-4">
<select class="form-control" id="sel1" th:field="*{project}">
<option th:each="project: ${projects}" th:value="${{project.projectId}}" th:text="${project.name}">1</option>
</select>
</div>
</div>
<div class="form-group">
<label class="col-md-4 control-label" for="textinput">People</label>
<div class="col-md-4">
<select class="form-control" id="sel1" th:field="*{people}" >
<option th:each="people: ${peoples}" th:value="${people.id}" th:text="${people.name}">1</option>
</select>
</div>
</div>
<div class="form-group">
<label class="col-md-4 control-label" for="textinput">Expense Type</label>
<div class="col-md-4">
<select class="form-control" id="sel1" th:field="*{expenseType}">
<option th:each="exp: ${expenseTypes}" th:value="${exp}" th:text="${exp}">1</option>
</select>
</div>
</div>
<div class="form-group">
<label class="col-md-4 control-label" for="textinput">Create
Expense</label>
<div class="col-md-4">
<input type="submit" class="btn btn- danger" value="Submit"/
</div>
</div>
Model Bean Class
#Data
#JsonIgnoreProperties(value = {"createdAt", "updatedAt"},
allowGetters = true)
#Entity
public class Expense {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long expenseId;
#Lob
private String description;
#OneToOne
#Cascade(CascadeType.ALL)
private People people;
private Double amount;
#Temporal(TemporalType.TIMESTAMP)
#CreatedDate
private Date createdAt;
#Temporal(TemporalType.TIMESTAMP)
#LastModifiedDate
private Date updatedAt;
#ManyToOne
#Cascade(CascadeType.ALL)
private Project project;
#Enumerated(EnumType.STRING)
private ExpenseType expenseType;
public Expense(String description, Double expense) {
this.description = description;
this.amount = expense;
}
public Expense() {
}
public void setCreatedAt(Date createdAt) {
this.createdAt = new Date();
}
public Date getUpdatedAt() {
return updatedAt;
}
#PreUpdate
public void setUpdatedAt() {
this.updatedAt = new Date();
}
}
Controller Snippet
#PostMapping(path="/createexpense")
public Expense addExpense(#ModelAttribute("expense") Expense expense ,BindingResult result){
log.debug(expense.toString());
expense.setPeople(peopleService.getPeople(expense.getPeople().getId()));
expense.setProject(flatProjectService.getFlatProjectById(expense.getProject().getProjectId()));
return expenseService.createExpense(expense);
}
#GetMapping(path="/createexpense")
public ModelAndView addExpense(ModelAndView modal){
//adding projects list and people list in expense view
modal.addObject("projects", flatProjectService.getAllProjects());
modal.addObject("peoples", peopleService.getAllPeoples());
modal.setViewName("createexpense");
modal.addObject("expense", new Expense());
modal.addObject("expenseTypes", ExpenseType.values());
return modal;
}
Error Logs
2018-07-22 18:22:44.010 DEBUG 25500 --- [nio-8080-exec-5] c.d.b.controller.HomeController : Expense(expenseId=null, description=hello, people=People(id=2, name=Avinash, peopleType=null, phoneNo=9504974665, address=Beside Maa Clinic, expense=[], createdDate=2009-06-01 13:45:30.0, updatedDate=2009-06-01 13:45:30.0), amount=5000.0, createdAt=null, updatedAt=null, project=null, expenseType=PAID)
2018-07-22 18:22:44.090 ERROR 25500 --- [nio-8080-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException: null
Looking at your HTML logic. I suspect issue is in Project Loop
You are defining th:field="*{project}"
but using as pro in option
Ideally it should be like this
<div class="form-group">
<label class="col-md-4 control-label" for="textinput">Project</label>
<div class="col-md-4">
<select class="form-control" id="sel1" th:field="*{project}">
<option th:each="project: ${projects}" th:value="${project.projectId}"
th:text="${pro.name}">1</option>
</select>
</div>
</div>

Spring mvc - POST request with #ModelAttribute cause unnecessary sql queries

I have a form with three select inputs, which are added from the db in the view. Everything is OK and the user can select for every select. The problem is that when I submit the form, the #ModelAttribute generates the same queries as the GET request (when these three selects are added into the view) and in the same, the select fields are empty after the POST.
#GetMapping("/road-assistance")
public String viewPage(Model model, Locale locale) {
model.addAttribute("roadAssistanceDto", roadAssistanceService.createRoadAssistanceDto(locale, null));
return "admin/roadassistance/view";
}
#PostMapping("/road-assistance")
public String createRoadAssistance(Model model, Locale locale,
final #Valid #ModelAttribute("roadAssistanceDto") RoadAssistanceDto roadAssistanceDto,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return "redirect:/";
}
return "admin/roadassistance/view";
}
Why the #PostMapping generates the same queries and in the same time, I don't have the info in the view/model?
the view -
<div class="row card-pagging">
<div class="col-sm-2 mt-3 offset-sm-2">
<label data-th-text="#{control.panel.roadassistance.country}"
class="control-label"
for="country">Country</label>
<select id="country" data-th-field="*{country}" class="form-control">
<option data-th-each="countryList : ${roadAssistanceDto.countryList}"
data-th-value="${countryList.id}"
data-th-text="${countryList.countryI18n[#locale].name}"></option>
</select>
</div>
<div class="col-sm-3 mt-3">
<label data-th-text="#{control.panel.roadassistance.region}" class="control-label"
for="region">Region</label>
<select data-th-field="*{region}" id="region" class="form-control">
<option value='' data-th-text="#{control.panel.roadassistance.chooseregion}"></option>
<option data-th-each="reg : ${roadAssistanceDto.regionList}" data-th-value="${reg.id}"
data-th-text="${reg.regionI18n[#locale].name}"></option>
</select>
</div>
<div class="col-sm-3 mt-3">
<label data-th-text="#{control.panel.roadassistance.city}" class="control-label"
for="region">City</label>
<select data-th-field="*{city}" id="city" class="form-control">
<option value="" data-th-text="#{control.panel.roadassistance.chooseregion}"></option>
<option data-th-each="city : ${roadAssistanceDto.cityList}" data-th-value="${city.id}"
data-th-text="${city.cityI18n[#locale].name}"></option>
</select>
</div>
</div>
And the RoadAssistanceDto -
public class RoadAssistanceDto implements Serializable {
private Long id;
private Country country;
private Region region;
private City city;
private List<Country> countryList;
private List<Region> regionList;
private List<City> cityList;
/* GETTERS AND SETTERS /*
}
Hm... I think that I notice the problem.. there is something workng when I'm binding the fields in the thymeleaf... but anyway, why is generating these queries?

Resources