Generate html select option from database in spring mvc app with thymeleaf - java

In spring based web app using hibernate I have a lists.html file where are select options codes reused in many views, now options will be transferred to database and my task is to populate those lists from db. This code will be rarely updated.This is example of list and its usage.
lists.html
<select th:fragment="typeList">
<option selected value=""></option>
<option th:value="|1|" th:text="|Type #1|"></option>
<option th:value="|2|" th:text="|Type #2|"></option>
<option th:value="|3|" th:text="|Type #3|"></option>
<option th:value="|4|" th:text="|Type #4|"></option>
</select>
usage
<li>
<label for="type" th:text="#{type.label}">type</label>
<select th:field="*{type}" th:include="html/fragments/lists :: typeList"></select>
</li>
What is the best method to build this lists.html from database dictionary?

My DTO
#Entity
#Table(name = "TableName")
public class Test {
#Id
private String Code;
private String Name;
private int price;
public Test() {}
public Test(String Code, String Name, int price) {
this.Code = Code;
this.Name = Name;
this.price = price;
}
public String getCode() {
return Code;
}
public String getName() {
return Name;
}
public int getPrice() {
return price;
}
}
View
List<Test> test = new ArrayList<>();
model.addAttribute("test", test);
List<Test> tests = testRepository.findAll();
model.addAttribute("tests", tests);
HTML
<select class="form-control" id="Order" name="Order">
<option value="">Select Test Order</option>
<option th:each="test : ${tests}"
th:value="${test.Code}"
th:text="${test.Code}+' : '+${test.Name}"></option>
</select>
</div>
Reference
Reference link

Related

Getting values from enum in thymeleaf

I'm using enum for select options in thymeleaf and I can't see them or insert them in the database. There is nothing in the dropdown list.
<div class="form-group">
<label for="roomType">Rooms</label>
<select class="form-select selectpicker show-tick" th:field="*{property.roomType}" id="rooms">
<option value="">Nothing selected</option>
<option th:each="property.roomType : ${T(com.realestate.petfriendly.entity.RoomType).values()}"
th:value="${property.roomType}"
th:text="${property.roomType}">
</option>
</select>
</div>
class
#Enumerated(EnumType.STRING)
#Column(name = "RoomType")
private RoomType roomType;
and enum
public enum RoomType {
GARSONJERA("garsonjera"), JEDNOIPOSOBAN("jednoiposoban"), DVOSOBAN("dvosoban"),
DVOIPOSOBAN("dvoiposoban"), TROSOBAN("trosoban"), TROIPOSOBAN("troiposoban"),
CERVOROSOBAN("cetvorosoban"), CETVOROIPOSOBAN("cetvoroiposoban"), VISESOBAN("visesoban");
private String roomType;
private RoomType(String roomType) {
this.roomType = roomType;
}
public String getRoomType() {
return this.roomType;
}
}
I'm not sure why it doesn't show me anything
that is available for me.
class
#Setter
#Getter
public class Demo {
private RoomType roomType;
}
enum
public enum RoomType {
GARSONJERA("garsonjera"), JEDNOIPOSOBAN("jednoiposoban"), DVOSOBAN("dvosoban"),
DVOIPOSOBAN("dvoiposoban"), TROSOBAN("trosoban"), TROIPOSOBAN("troiposoban"),
CERVOROSOBAN("cetvorosoban"), CETVOROIPOSOBAN("cetvoroiposoban"), VISESOBAN("visesoban");
private final String roomType;
private RoomType(String roomType) {
this.roomType = roomType;
}
public String getRoomType() {
return this.roomType;
}
}
controller:
#Controller
#RequestMapping( "test")
public class TestController {
#GetMapping("demo")
public String demo(Model model){
Demo demo = new Demo();
demo.setRoomType(RoomType.CERVOROSOBAN);
model.addAttribute(demo);
return "test/demo";
}
}
HTML:
<div class="form-group">
<label for="rooms">Rooms</label>
<select class="form-select selectpicker show-tick" th:field="*{demo.roomType}" id="rooms">
<option value="">Nothing selected</option>
<option th:each="value : ${T(com.bluray.boot.business.test.RoomType).values()}"
th:value="${value}"
th:text="${value}">
</option>
</select>
</div>
I use spring-boot 2.3.6.release

get enum class values to dropdown list

I have an enum class and I want to get values of enum class into the dropdown list. The following code shows how I tried to do it. (I just add enum values as values of options in select). but I want to get data from enum class as the dropdown item.
-Enum class
public enum Status implements BaseEnum {
PENDING(0, "PENDING"), PROCESS(1, "PROCESS"), REJECT(2, "REJECT"));
private int code;
private String name;
private Status(int code, String name) {
this.code = code;
this.name = name;
}
public int getCode() {
return code;
}
public String getName() {
return name;
}
private static final Map<Integer, Status> LOOKUP = new HashMap<Integer, Status>();
static {
for (Status status: EnumSet.allOf(Status.class)) {
LOOKUP.put(status.getCode(), status);
}
}
public static Status fromCode(int code) {
return LOOKUP.get(code);
}
}
-Dropdown list
<select class="form-control" id="status">
<option value="${statusDTO.status}">${statusDTO.status}</option>
<option value="PENDING">PENDING</option>
<option value="PROCESS">PROCESS</option>
<option value="REJECT">REJECT</option>
</select>
If you want to show all values in your Status enum in dropdown list, you can do as follows:
<select id="status" name="status">
<option th:each="status : ${T(com.stackoverflow.enums.Status).values()}"
th:value="${status}" th:text="${status}"></option>
</select>
You can do as follows to show a different value:
<select id="status" name="status">
<option th:each="status : ${T(com.stackoverflow.enums.Status).values()}"
th:value="${status}" th:text="${status.name}"></option>
</select>
If you want to highlight your choice, you can use if statement:
<select id="status" name="status">
<option
th:each="status : ${T(com.stackoverflow.enums.Status).values()}"
th:value="${status}" th:text="${status.name}"
th:selected="${status == statusDTO.status}"></option>
</select>
You can reproduce these examples, you can review this article for different enum scenarios or this article for different select scenarios.

MVC: Value in dropdown menu doesn't set to selected value - remains 0

This is a spring Boot application that uses thymeleaf template manager. It has a simple form with dropdown menu. Options are populated from database, both their names (or ids) can be displayed correctly on form but after selecting option and submiting form value of given selected variable remains 0.
While I get the correct value of variable content, categoryId always has value 0 after submit (or null if I change it's type from int to Integer).
I'm guessing that model isn't correctly "linked" to jokeForm but I don't know how to link it correctly. I was following example 1. I hope someone can eassily spot the problem just by quickly looking at my code. Code breakes in method submitForm().
HTML form:
<html>
<body>
<form action="#" th:action="#{/new}" th:object="${jokeForm}" method="post">
<table>
<tr>
<td>Content:</td>
<td><input type="text" th:field="*{content}" /></td>
<td th:if="${#fields.hasErrors('content')}" th:errors="*{content}">Content Error</td>
</tr>
<tr>
<td>Category:</td>
<td>
<select name="categoryId" th:field="*{categoryId}">
<option value="0" th:each="category : ${categories}"
th:value="${category.id}"
th:utext="${category.name}"/>
<!-- <option th:each="category : *{categories}"
th:value="*{category.id}"
th:utext="*{category.name}"/> -->
</select>
</td>
<td th:if="${#fields.hasErrors('categoryId')}" th:errors="*{categoryId}">category Error</td>
</tr>
<tr>
<td><button type="submit">Submit</button></td>
</tr>
</table>
</form>
</body>
</html>
Controller
#GetMapping("/new")
public String showForm( Model model) {
DEBUG("showForm");
JokeForm form = new JokeForm();
categories = categoryRepository.findAll();
DEBUG(categories.get(0).toString());
DEBUG(categories.get(1).toString());
//form.setCategories(categories); //not working
model.addAttribute("jokeForm", form);
model.addAttribute("categories",categories);
return "form";
}
#PostMapping("/new")
#ResponseBody
public String submitForm(#ModelAttribute JokeForm jokeForm) {
DEBUG("submitForm");
//String content = jokeForm.getContent();
DEBUG(jokeForm.getContent());
DEBUG(jokeForm.getCategoryId().toString());
Joke j = new Joke();
j.setContent(jokeForm.getContent());
//j.setCategoryId(jokeForm.getCategoryId());
//DEBUG(Integer.toString(jokeForm.getCategoryId()));
//CAUSES ERROR value of CategoryId is Integer -> null System.out.println(Integer.toString(jokeForm.getCategoryId()));
//PRODUCES ERROR value of CategorId is int (because no category matches) j.setCategory(categoryRepository.findById(jokeForm.getCategoryId().intValue()).get(0));
jokeRepository.save(j); //save
return "Saved";
}
JokeForm
public class JokeForm {
#NotEmpty(message = "content may not be empty")
private String content;
#NotEmpty(message = "category may not be empty")
private int categoryId; //int-> 0, Integer -> null
/*
#NotEmpty(message = "category may not be empty")
private Category category;
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
}
private List<Category> categories;
public List<Category> getCategories() {
return categories;
}
public void setCategories(List<Category> categories) {
this.categories = categories;
} */
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Integer getCategoryId() {
return categoryId;
}
public void setCategory(Integer categoryId) {
this.categoryId = categoryId;
}
}
You set value="0" for all options.
<select> should be:
<select th:field="*{categoryId}">
<option th:each="category : ${categories}"
th:value="${category.id}"
th:utext="${category.name}"/>
<!-- <option th:each="category : *{categories}"
th:value="*{category.id}"
th:utext="*{category.name}"/> -->
</select>
Edit:
and add (setter) setCategoryId() in JokeForm class

[Failed to convert property value of type 'java.lang.String[]' to required type 'java.util.List' for property

I am working with Thymeleaf and trying to do some object binding, but I do not know how to do it if I have an object with a list. Let me explain:
My model:
#Entity
public class Project {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotNull
private String name;
#NotNull
#Lob
private String description;
#NotNull
private Date startDate;
private String status;
#ManyToMany
private List<Role> rolesNeeded;
#ManyToMany
private List<Collaborator> collaborators;
public Project() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public List<Role> getRolesNeeded() {
return rolesNeeded;
}
public void setRolesNeeded(List<Role> rolesNeeded) {
this.rolesNeeded = rolesNeeded;
}
public List<Collaborator> getCollaborators() {
return collaborators;
}
public void setCollaborators(List<Collaborator> collaborators) {
this.collaborators = collaborators;
}
}
My html form:
<form method="post" action="addproject" th:object="${project}">
<div>
<label for="project_name"> Project Name:</label>
<input th:field="*{name}" type="text" name="project_name"/>
</div>
<div>
<label for="project_description">Project Description:</label>
<textarea th:field="*{description}" rows="4" name="project_description"></textarea>
</div>
<div>
<label for="project_status">Project Status:</label>
<div class="custom-select">
<span class="dropdown-arrow"></span>
<select th:field="*{status}" name="project_status">
<option value="active">Active</option>
<option value="archived">Archived</option>
<option value="not_started">Not Started</option>
</select>
</div>
</div>
<div>
<label for="project_roles">Project Roles:</label>
<ul class="checkbox-list">
<li th:each="role : ${roles}">
<input th:field="*{rolesNeeded}" type="checkbox" name="project_roles" th:value="${role}"/>
<span class="primary" th:text="${role.name}"> Developer</span>
</li>
</ul>
</div>
<div class="actions">
<input type="submit" value="Save" class="button"/>
Cancel
</div>
</form>
And I am getting the error:
ERROR!!!!: Field error in object 'project' on field 'rolesNeeded':
rejected value
[com.imprender.instateam.model.Role#145d6cd4,com.imprender.instateam.model.Role#73020d6f];
codes
[typeMismatch.project.rolesNeeded,typeMismatch.rolesNeeded,typeMismatch.java.util.List,typeMismatch];
arguments
[org.springframework.context.support.DefaultMessageSourceResolvable:
codes [project.rolesNeeded,rolesNeeded]; arguments []; default message
[rolesNeeded]]; default message [Failed to convert property value of
type 'java.lang.String[]' to required type 'java.util.List' for
property 'rolesNeeded'; nested exception is
java.lang.IllegalStateException: Cannot convert value of type
'java.lang.String' to required type
'com.imprender.instateam.model.Role' for property 'rolesNeeded[0]': no
matching editors or conversion strategy found]
Basically, as far as I understood, the checkbox input returns a String[], but my object needs a list, so the binding cannot be perfomed.
How could I bind the array in the list? (do you have an example?)
Thank you.
If Your Role bean has active boolean property, You could do something like this (simplified):
<ul class="checkbox-list">
<li th:each="role,stat : ${project.rolesNeeded}">
<input th:field="*{rolesNeeded[__${stat.index}__].active}" type="checkbox"/>
<input th:field="*{rolesNeeded[__${stat.index}__].name}" type="hidden"/>
<span class="primary" th:text="${role.name}">Developer</span>
</li>
</ul>
If it does not, you could store the rolesNeeded in the hidden fields and populate them with javascript.

Spring MVC syntactically incorrect request

I'm creating a web application using Spring MVC, but all my POST request result in "The request sent by the client was syntactically incorrect". As an example, this is a search form:
<form id="projectsForm" action="#" th:action="#{/projects}" th:object="${projectsForm}" method="post">
<input type="hidden" th:field="*{page}" />
<div id="search">
<select id="expert" th:field="*{expert}">
<option value="">(select expert)</option>
<option th:each="expert : ${experts}"
th:value="${expert.id}"
th:text="${expert.firstName + ' ' + expert.lastName}"></option>
</select>
<select id="company" th:field="*{company}">
<option value="">(select company)</option>
<option th:each="company : ${companies}"
th:value="${company.id}"
th:text="${company.name}"></option>
</select>
<input type="text" id="query" th:field="*{query}" />
<button class="search" onclick="firstPage()">Search</button>
<button class="empty" onclick="empty()">Erase</button>
</div>
The form object class looks like this:
public class ProjectsForm {
private Expert expert;
private Company company;
private String query;
private Integer page = 0;
private Integer pages;
public Expert getExpert() {
return expert;
}
public void setExpert(Expert expert) {
this.expert = expert;
}
public Integer getPage() {
return page;
}
public void setPage(Integer page) {
this.page = page;
}
public Integer getPages() {
return pages;
}
public void setPages(Integer pages) {
if (pages > 0 && page >= pages) {
page = pages - 1;
}
this.pages = pages;
}
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
public String getQuery() {
return query;
}
public void setQuery(String query) {
this.query = query;
}
}
And this is the controller method:
#RequestMapping(value="/projects", method=RequestMethod.POST)
public String projectsPost(#ModelAttribute("projectsForm") ProjectsForm projectsForm, ModelMap model) {
sessionBean.setProjectsForm(projectsForm);
Page<Project> projectPage = projectService.findAll(projectsForm.getPage(), ProjectController.PAGESIZE, projectsForm.getExpert(), projectsForm.getCompany(), projectsForm.getQuery());
List<Project> projects = projectPage.getContent();
model.addAttribute("projects", projects);
projectsForm.setPage(projectPage.getNumber());
projectsForm.setPages(projectPage.getTotalPages());
model.addAttribute("projectsForm", projectsForm);
return "projects";
}
Chrome tells me the form data look like this:
page=0&expert=&company=&query=
Is there an obvious error, or is there any way I can diagnose this problem? Adding log4j.logger.org.springframework.web=DEBUG to log4j.properties didn't give me any more information. What also puzzles me is that the exact same code worked fine in a Spring Boot jar application.

Categories

Resources