how to bind form data to list<object> - spring-boot

ResizeDTO
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
#Data
#NoArgsConstructor
#AllArgsConstructor
public class ResizeDTO {
private String group_id;
private String width;
private String height;
}
View(thymeleaf)
<form action="resize" method="post">
<div th:each="m : ${list}">
<input type="text" name="group_id" required>
<input type="text" name="width" required>
<input type="text" name="height" required>
</div>
</form>
Controller
#GetMapping("/config/resize")
public String Config_Resize(#RequestParam(required = false) String group_id, Model model){
model.addAttribute("group_id", group_id);
return "config/resize";
}
#PostMapping("/config/resize")
public String Config_Resize_Update(ResizeDTO resizeDTOList){
resizeService.updateResize(resizeDTOList);
return "redirect:resize";
}
i want to bind data for 'list'
like
ResizeDTO(group_id=id1, width=1024, height=720), ResizeDTO(group_id=id2, width=2560, height=1440), ResizeDTO(group_id=id3, width=1080, height=860)
how can i do?

You have to change field names of the input to include indexes [x] like so
<div th:each="listItem, iter : ${list}">
<input type="text" th:field="${list[__${iter.index}__].group_id}" required>
<input type="text" th:field="${list[__${iter.index}__].width}" required>
<input type="text" th:field="${list[__${iter.index}__].height}" required>
</div>
See this article for more info about working with list in thymeleaf https://www.baeldung.com/thymeleaf-list#list-selection-expression

Related

How to iterate and save 2 objects with thymeleaf?

I dont know how fix this error, i saw some articles about that but nothing works.
Error
Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errorsField error in object 'pupil' on field 'curse': rejected value [ModelCurse(id=2, name=PHP, division=2da, pupilList=[], teacherList=[])];
[Failed to convert property value of type 'java.lang.String' to required type 'com.example.administrator.administrator.model.ModelCurse' for property 'curse';
HTML
<form th:action="#{/pupilController/add}" th:object="${pupil}" method="post">
<div class="form-row">
<div class="form-group col-md-6">
<label>Name</label>
<input type="text" class="form-control" th:field="*{name}" placeholder="Name">
</div>
<div class="form-group col-md-6">
<label>Last Name</label>
<input type="text" class="form-control" th:field="*{lastName}" placeholder="Last Name">
</div>
<div class="form-group col-md-6">
<label>Age</label>
<input type="number" class="form-control" th:field="*{age}" placeholder="Age">
</div>
<div class="form-group col-md-6">
<label>Phone Number</label>
<input type="text" class="form-control" th:field="*{phoneNumber}" placeholder="Phone Number">
</div>
<div class="form-group col-md-6">
<select th:field="*{curse}" class="form-control">
<option th:each="curso : ${curses}"
th:value="${curso}"
th:text="${curso.name}"></option>
</select>
</div>
</div>
<input type="submit" name="btnInsert" class="btn btn-primary" value=Añadir>
</form>
Controller
#GetMapping("/addPupil")
public ModelAndView login(Model model){
ModelAndView mav = new ModelAndView("addpupil");
List<ModelCurse> modelCurses = curseService.getAllCurses();
mav.addObject("pupil",new ModelPupil());
mav.addObject("curses",modelCurses);
return mav;
}
#PostMapping("/add")
public RedirectView addPupil(#ModelAttribute("pupil")ModelPupil modelPupil){
pupilService.addPupil(modelPupil);
return new RedirectView("/pupilController/pupilList");
}
DTO
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#ToString
public class ModelCurse {
private long id;
private String name;
private String division;
private List<ModelPupil> pupilList;
private List<ModelTeacher> teacherList;
}
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#ToString
public class ModelPupil {
private long id;
private String name;
private String lastName;
private int age;
private int phoneNumber;
private ModelCurse curse;
}
When we submit the form, the value of selected option is sent as Text or String in HTTP POST. So, if you are expecting that Spring would automatically convert that String value of curse to object of type ModelCurse, then your assumption is wrong. But Spring does provide us a way to do it using Java beans PropertyEditorSupport. Here you can extend this class, and provide your own implementation on how to convert that String to the required object.

Spring & Thymeleaf form

adding in form is trivial when I have only one object like here:
<form th:action="|#{group/save}/${id}|" th:object="${groupForm}" method="post" class="col m8 s8 offset-m2">
<div class="row">
<div class="input-field">
<input th:field="${groupForm.name}" id="name" type="text" required="required"/>
<label for="name">Nazwa:</label>
</div>
</div>
<div class="row">
<button class="btn-success" type="submit" name="save">Wyślij<i class="mdi-content-send right"></i></button>
</div>
</form>
but let's assume that groupForm have list of customer
public class Customer{
private long id;
private String firstName;
private String lastName;
private String nick;
}
How can I add 5 Customers into list in class Group? I want to achive in one request.
Assuming that your Group class looks something like this:
public class Group {
private List<Customer> customers;
}
Try this:
<input th:field="*{customers[0].name}" type="text" required="required"/>
<input th:field="*{customers[1].name}" type="text" required="required"/>
<input th:field="*{customers[2].name}" type="text" required="required"/>
<input th:field="*{customers[3].name}" type="text" required="required"/>
<input th:field="*{customers[4].name}" type="text" required="required"/>

I can not update my entity using Hibernate, Spring MVC, Thymleaf

Hello I want to update User entity, so in the form edit.html i'm using thymeleaf:
<form action="#" th:action="#{/{id}/edit(id=${user.id})}"
th:object="${user}" method="post">
<div class="md-form">
<input type="text" th:field="*{firstName}"
th:value="${user.firstName}" name="firstName" id="firstName"
class="form-control" /> <label class="active" for="firstName">Prénom</label>
</div>
<div class="md-form">
<input type="text" th:field="*{lastName}"
th:value="${user.lastName}" name="lastName" id="lastName"
class="form-control" /> <label class="active" for="lastName">Nom</label>
</div>
<div class="md-form">
<input type="text" th:field="*{email}" th:value="${user.email}"
name="email" id="email" class="form-control" /> <label
class="active" for="email">email</label>
</div>
<div class="md-form">
<input type="text" th:field="*{password}"
th:value="${user.password}" name="password" id="password"
class="form-control" /> <label class="active" for="password">mot
de passe</label>
</div>
<div class="md-form">
<input type="text" th:field="*{occupation}"
th:value="${user.occupation}" name="occupation" id="occupation"
class="form-control" /> <label class="active" for="occupation">profession</label>
</div>
<div class="md-form">
<input type="text" th:field="*{ville}" th:value="${user.ville}"
name="ville" id="ville" class="form-control" /> <label
class="active" for="ville">ville</label>
</div>
<div>
<input class="btn btn-sm btn-primary waves-effect btn-rounded"
type="submit" value="modifier" />
</div>
</form>
User.java:
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue
private Long id;
private String firstName;
private String lastName;
private String userName;
private int age;
private String ville;
private String email;
private String password;
private String phone;
private String company;
private String occupation;
private String img_profil;
#ManyToMany(mappedBy = "users", cascade = { CascadeType.ALL })
private Set<Discussion> discussion;
UserController.java
#GetMapping("/{userName}/edit")
public String editUser(#PathVariable String userName, Model model) {
User user = ur.findByUserName(userName).get(0);
model.addAttribute(user);
return "edit";
}
#PostMapping("/{id}/edit")
public String updateUser(#ModelAttribute("user") User user, #PathVariable("id") Long id) {
user = ur.findOne(id);
ur.save(user);
return "redirect:/find/" + user.getUserName();
}
UserRepository.java
#Repository
public interface UserRepository extends CrudRepository<User, Long> {
List<User> findByUserName(String userName);
}
PROBLEM is in the console I do not see update request (generated by Hibernate), nothing is changed on the database.
Make the following change in UserController.java:
#PostMapping("/{id}/edit")
public String updateUser(
#ModelAttribute("user") User user,
#PathVariable("id") Long id)
{
//user = ur.findOne(id);
user.setId(id);
ur.save(user);
return "redirect:/find/" + user.getUserName();
}

How to Bind the list data thymeleaf html from to spring controller?

This is my Controller class
package com.myblog.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import com.myblog.model.User;
#Controller
public class UserController {
private static final Logger log = LoggerFactory.getLogger(UserController.class);
#GetMapping(value="/user")
public String getUser(Model model){
model.addAttribute("user", new User());
return "user";
}
#PostMapping(value="/user")
public String postUser(#ModelAttribute("user") User user){
log.info("user :"+user);
return "user";
}
}
This is My Model class
user.java
package com.myblog.model;
import java.util.ArrayList;
import java.util.List;
public class User {
private int id;
private String name;
private List<Address> address=new ArrayList<Address>();
#Override
public String toString() {
return "User [name=" + name + ", address=" + address + "]";
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Address> getAddress() {
return address;
}
public void setAddress(List<Address> address) {
this.address = address;
}
}
address.java
package com.myblog.model;
public class Address {
private int id;
private String street;
private String city;
public int getAddid() {
return addid;
}
public void setAddid(int addid) {
this.addid = addid;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
This is my thymeleaf HTML page
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Page Title</title>
<link href="/static/css/bootstrap.min.css" rel="stylesheet" media="screen" th:href="#{css/bootstrap.min.css}"/>
<script src="/static/js/bootstrap.min.js" th:src="#{js/bootstrap.min.js}"></script>
</head>
<body>
<div class="container">
<h1> User Account</h1>
<form class="form-horizontal" th:action="#{/user}" method="POST" th:object="${user}">
<div class="form-group">
<label for="inputDescription" class="col-sm-2 control-label">Full Name</label>
<div class="col-sm-5">
<input type="text" class="form-control" name="name" placeholder="Full name"/>
</div>
</div>
<div class="form-group">
<label for="inputDescription" class="col-sm-2 control-label">Address</label>
<div class="col-sm-5">
<input type="text" class="form-control" name="address.city" placeholder="City"/>
</div>
</div>
<div class="form-group">
<label for="inputDescription" class="col-sm-2 control-label">Street</label>
<div class="col-sm-5">
<input type="text" class="form-control" name="address.street" placeholder="street" />
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label"></label>
<div class="col-sm-10">
<input type="submit" class="btn btn-primary" value="Add"/>
</div>
</div>
</form>
</div>
</body>
</html>
in controller user object does not bind the data into address model object.
output is user :user[name="name",address[]]
Your form seems to only manage one adress, but your domain model specifies a list of adresses. In this case you would need to name your input fields like address[0].street for the first address and so on.
So I'd consider to use a thymleaf iterator (th:each) to make all addresses manageable in your form. Then use th:field instead of defining name attributes. This should solve your problem.
<form class="form-horizontal" th:action="#{/user}" method="POST" th:object="${user}">
<div class="form-group">
<label for="inputDescription" class="col-sm-2 control-label">Full Name</label>
<div class="col-sm-5">
<input type="text" class="form-control" th:field="*{name}" placeholder="Full name"/>
</div>
</div>
<div class="form-group">
<label for="inputDescription" class="col-sm-2 control-label">Address</label>
<div class="col-sm-5">
<input type="text" class="form-control" th:field="*{address[0].city}" placeholder="City"/>
</div>
</div>
<div class="form-group">
<label for="inputDescription" class="col-sm-2 control-label">Street</label>
<div class="col-sm-5">
<input type="text" class="form-control" th:field="*{address[0].street}" placeholder="street" />
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label"></label>
<div class="col-sm-10">
<input type="submit" class="btn btn-primary" value="Add"/>
</div>
</div>
</form>

How to update object with relation to list of objects via thymeleaf form

I am in trouble :/ I have one object that has a list of another objects and I want to change this list via select box and inputs, but when I submit this, the list is empty
Here is my code (model, thymelaf form, controller):
public class BetConfigVM {
private long id;
private String name;
private List<BetPriorityVM> betPriorities;
....getters and setters
}
public class BetPriorityVM {
private long id;
private CourseType courseType;
private BigDecimal minCourse;
private BigDecimal maxCourse;
....getters and setters
}
<form action="#" th:action="#{/betConfigSaveOrUpdate}" th:object="${config}" method="post">
<input type="text" th:field="*{name}" />
<span th:field="*{betPriorities}" th:each="prio : *{betPriorities}">
<select>
<option th:each="type : ${T(com.model.database.CourseType).values()}"
th:value="${type}" th:text="${type}" th:selected="${prio.courseType == type}">
</option>
</select>
<input type="text" th:field="${prio.minCourse}" />
<input type="text" th:field="${prio.maxCourse}" />
</span>
<input type="submit" th:value="Save" name="action"/>
</form>
#RequestMapping(value = "/betConfigSaveOrUpdate", method = RequestMethod.POST)
public String saveOrUpdateUser(#ModelAttribute("config") BetConfigVM configVM, #RequestParam String action, Model model) {
System.out.println(configVM.getName());
System.out.println("Size " + configVM.getBetPriorities().size());
model.addAttribute("config", configVM);
return "user/betConfigEdit";
}
Do you have any idea how to pass the changed list in the object?
EDIT:
Adding controller part that will show the form:
#RequestMapping(value = "/changeBetConfig", method = RequestMethod.GET)
public String changeBetConfig(Model model, #RequestParam("id") long id) {
BetConfig betConfig = betConfigRepository.findById(id);
BetConfigVM configVM = new BetConfigVM(betConfig);
model.addAttribute("config", configVM);
return "user/betConfigEdit";
}
I found a solution..the form has to look like this:
<form action="#" th:action="#{/betConfigSaveOrUpdate}" th:object="${config}" method="post">
<input type="text" th:field="*{name}" />
<span th:each="prio, rowStat : *{betPriorities}">
<select th:field="*{betPriorities[__${rowStat.index}__].courseType>
<option th:each="type : ${T(com.model.database.CourseType).values()}"
th:value="${type}" th:text="${type}" th:selected="${prio.courseType == type}">
</option>
</select>
<input type="text" th:field="*{betPriorities[__${rowStat.index}__].minCourse}" />
<input type="text" th:field="*{betPriorities[__${rowStat.index}__].maxCourse}" />
</span>
<input type="submit" th:value="Save" name="action"/>

Resources