How to represent 2 model objects inside the thymeleaf template - spring

i am working in this spring-boot project and i am returning a ModelAndView object from my controller method , i have added 2 objects to the ModelAndView. this part is working and i want to know how to represent the values inside the thymeleaf template.
public ModelAndView showEdit(#PathVariable int id,Customer cust,Model model){
ModelAndView view = new ModelAndView();
view.setViewName("editCustom");
view.addObject("cust",cust);
view.addObject("log",login);
}
inside the thymeleaf template.
<form action="#" th:action="#{/save}" th:object="${cust}" method="post">
Name:<input type="text" th:field="*{name}" />
i can fetch values in cust but i dont know how to get values from login.
i tried this but its not working.note that all input tags are inside the same form.
<input type="text" id="user" name="user" value="${login.uname}"/>

In your model you are adding login details as log and in your view your are using login
view.addObject("log",login);
versus
${login.uname}
Also thymeleaf uses an attribute processor which process attributes prefixed with th. Instead of using value use th:value as follows
<input type="text" id="user" name="user" th:value="${log.uname}"/>

Related

Thymeleaf set default value [duplicate]

I am programming in Spring and using Thymeleaf as my view, and am trying to create a form where users can update their profile. I have a profile page which lists the user's information (first name, last name, address, etc), and there is a link which says "edit profile". When that link is clicked it takes them to a form where they can edit their profile. The form consists of text fields that they can input, just like your standard registration form.
Everything works fine, but my question is, when that link is clicked, how do I add the user's information to the input fields so that it is already present, and that they only modify what they want to change instead of having to re-enter all the fields.
This should behave just like a standard "edit profile" page.
Here is a segment of my edit_profile.html page:
First Name:
Here is the view controller method that returns edit_profile.html page:
#RequestMapping(value = "/edit", method = RequestMethod.GET)
public String getEditProfilePage(Model model) {
model.addAttribute("currentUser", currentUser);
System.out.println("current user firstname: " + currentUser.getFirstname());
model.addAttribute("user", new User());
return "edit_profile";
}
currentUser.getFirstname() prints out the expected value, but I'm getting blank input values in the form.
Thanks.
Solved the problem by removing th:field altogether and instead using th:value to store the default value, and html name and id for the model's field. So name and id is acting like th:field.
I'm slightly confused, you're adding currentUser and a new'd user object to the model map.
But, if currentUser is the target object, you'd just do:
<input type="text" name="firstname" value="James" th:value="${currentUser.firstname}" />
From the documentation:
http://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf.html
I did not have a form with input elements but only a button that should call a specific Spring Controller method and submit an ID of an animal in a list (so I had a list of anmials already showing on my page). I struggled some time to figure out how to submit this id in the form. Here is my solution:
So I started having a form with just one input field (that I would change to a hidden field in the end). In this case of course the id would be empty after submitting the form.
<form action="#" th:action="#{/greeting}" th:object="${animal}" method="post">
<p>Id: <input type="text" th:field="*{id}" /></p>
<p><input type="submit" value="Submit" /> </p>
</form>
The following did not throw an error but neither did it submit the animalIAlreadyShownOnPage's ID.
<form action="#" th:action="#{/greeting}" th:object="${animal}" method="post">
<p>Id: <input type="text" th:value="${animalIAlreadyShownOnPage.id}" /></p>
<p><input type="submit" value="Submit" /> </p>
</form>
In another post user's recommended the "th:attr" attribute, but it didn't work either.
This finally worked - I simply added the name element ("id" is a String attribute in the Animal POJO).
<form action="#" th:action="#{/greeting}" th:object="${animal}" method="post">
<p>Id: <input type="text" th:value="${animalIAlreadyShownOnPage.id}" name="id" /></p>
<p><input type="submit" value="Submit" /> </p>
</form>

Multiple similar forms in same page

In Spring Boot with Thymeleaf, I have a page that should handle two forms corresponding to a same model Person. Each form can be submitted separately, so I use two methods in the controller:
#PostMapping(value="/", params={"submitFather"})
public String submitFather(
#ModelAttribute("fatherForm") Person fatherForm,
#ModelAttribute("motherForm") Person motherForm,
Model model) {
// ... Process fatherForm
// Return the updated page
model.addAttribute("fatherForm", fatherForm);
model.addAttribute("motherForm", motherForm);
return "index.html";
}
#PostMapping(value="/", params={"submitMother"})
public String submitMother(
#ModelAttribute("fatherForm") Person fatherForm,
#ModelAttribute("motherForm") Person motherForm,
Model model) {
// ... Process motherForm
// Return the updated page
model.addAttribute("fatherForm", fatherForm);
model.addAttribute("motherForm", motherForm);
return "index.html";
}
In my template:
<form id="fatherForm" th:object="${fatherForm}" method="post">
<label for="firstName">First name</label>
<input type="text" th:field="*{firstName}"><br>
<!-- ... other Person fields -->
<input type="submit" name="submitFather" value="Order">
</form>
<form id="motherForm" th:object="${motherForm}" method="post">
<label for="firstName">First name</label>
<input type="text" th:field="*{firstName}"><br>
<!-- ... other Person fields -->
<input type="submit" name="submitMother" value="Order">
</form>
The issue I have is that this leads to HTML IDs clashes. There will be for example two <input> with id firstName. This causes invalid HTML and interference between the fields from the two forms when submitted.
One solution would be to have two models, Father and Mother with fields named such as fatherFirstName to ensure no duplicate HTML IDs. But this leads to substantial code duplication, and long and different field names (while only the HTML IDs need to be different).
How can this be solved? Is there a way to tell Spring to prefix ids with some string while ensuring I can still use the same Person model for the two forms?

Create urls using forms in Thymeleaf

I am new to Thymeleaf, and I have an issue with dynamically creating URLs using forms.
I have a simple spring boot app that stores objects in a database, and I can query the database using simple urls. For instance, the url /distance/0.3 would return objects whose distance attribute is lower than or equal to 0.3. These urls work perfectly when I edit them in the browser.
I would like users to be able to set these search values themselves. I tried to create a simple form to create the above url with user inputs, but I am getting the following error:
Neither BindingResult nor plain target object for bean name 'dist' available as request attribute
I have tried with this in the html document:
<form th:action="#{/distance/{pathParam}(pathParam=${dist}}">`
<p>Distance: <input type="text" th:field="*{dist}" /></p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
and trying various answers from this discussion, but with no luck.
I have also tried to use the controller as suggested here, with this in the controller:
#GetMapping("/distance/search/")
public String userSetDistance(#RequestParam("dist") String dist) {
return "redirect:/distance/" + dist;
}
and this in the html file:
<form th:action="#{/distance/search/}">
<p>Distance: <input type="text" th:field="*{dist}" /></p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
But this did not work either.
Could you please help me with this? The idea is simple but I cannot get something that works... thank you!
UPDATE
Based on the below answer from MohamedSanaulla, I decided to use the controller to do this, created a "forms" object with the required fields and edited my code as follows:
<form action="#" th:action="#{/distance/search}" th:object="${param}" method="post">`
<p>Distance: <input type="text" th:field="*{dist}"/></p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
#PostMapping("/distance/search")
public String userGetClose(#ModelAttribute ("param") Forms form) {
String distance = String.valueOf(form.getDist());
return "redirect:/distance/" + distance;
}
Ideally I wanted to create and call the url directly from the html page, to avoid going back to the controller just to create the url, but this works fine.
You have to either use ModelMap or Model in your controller and then use addAttribute to set the dist:
public String controllerMethod(#RequestParam("dist") String dist,
Model model){
model.addAttribute("dist", dist);
return "viewName";
}
Or Thymeleaf provides context object to get query params like ${param.dist} directly in your HTML
Update:
Just saw that there is a redirect: in the controller. So the dist is no longer available in the request param and hence ${param.dist} will not work. The easier solution is to use ModelMap and put the dist as part of the view model.

how to pass parameter from HTML with Thymeleaf to Spring Controller?

I have a controller in Spring Boot that needs to recieve a parameter and an object by POST. The parameter is NOT an object or part of if.
Here is the Thymeleaf form without the parameter. It works fine in a stand-alone page, but the same code does not work when I use it in a page that shows an article:
<form th:action="#{/addcomment}" th:object="${comment}" method="post">
<input type="text" th:field="*{commenttext}" />
<button type="submit">send</button>
</form>
because when I add the
<input type="hidden" th:field="*{id}" th:with="id=1" value="${id}"/>
or
<input type="hidden" th:field="*{id}"/>
or
<input type="hidden" th:field="*{id}" value="1"/>
my Controller prints 0 in the console, when the value should be 1... (and even if I change it to value="true".... this comes from the Chrome console:
<input type="hidden" class="sr-only" value="0" id="id" name="id" />
no matter what I use
#RequestMapping(value = "/addcomment", method = RequestMethod.POST)
ModelAndView addStatus(ModelAndView modelAndView, #Valid Comment comment, #RequestParam("id") Long id, BindingResult result) {
Comment commentform = new Comment();
Announcement announcement = announcementService.readAnnouncement(id);
String sanatizedcommenttext = htmlPolicy.sanitize(comment.getCommenttext());
commentform.setCommenttext(sanatizedcommenttext);
commentform.setDate(new Date());
commentform.setAnnoucements(announcement);
modelAndView.setViewName("addcomment");
if (!result.hasErrors()) {
commentService.createComment(commentform);
modelAndView.getModel().put("comment2th", new Comment());
modelAndView.setViewName("redirect:/addcomment");
}
return modelAndView;
}
By the way, the parameter is in the url (but I would like to know how to send it to the controller independently of where it is located).
thanks for your help!
You only have to add this changes
<input type="hidden" name="paramName" value="1"/>
In your Controller
#RequestMapping(value = "/addcomment", method = RequestMethod.POST)
ModelAndView addStatus(ModelAndView modelAndView, #Valid Comment comment, #RequestParam("paramName") Long id, BindingResult result) {
The problem was, that you were using the thymeleaf tags for input fields, then Spring thinks the attribute id its inside the object Comment, but it's not your case, so you have to use normal input tag.

how to intercept #modelattribute binding

Everyone.
I am using spring mvc framework, and spring form tag. I found unexpected thing when using form dynamically. For example,
public class Person {
public List<Car> myCars = new ArrayList<Car>();
// getter and setter
}
below code is html form
<form:form modelAttribute="car" ...>
<input type="hidden" name="myCars[0].id">
<input type="text" name="myCars[0].name">
<input type="hidden" name="myCars[1].id">
<input type="text" name="myCars[1].name">
<input type="hidden" name="myCars[2].id">
<input type="text" name="myCars[2].name">
</form:form>
and next code is a spring form controller
#Controller
#SessionAttribute({"car"})
public class CarController {
...
#RequestMapping(".....")
public String form(#ModelAttribute Car car, BindingResult result, ...) {
if (result.hasErrors()) {
....
return viewName;
}
....
return "redirect:/" + someWhere;
}
}
1) I entered data into html form.
2) I can confirm that there are 3 Car objects in car.getMyCars()
3) There are some errors as binding, so it's redirected to viewName
4) I changed html form using jQuery like this
<form:form modelAttribute="car" ...>
<input type="hidden" name="myCars[0].id">
<input type="text" name="myCars[0].name">
<input type="hidden" name="myCars[1].id">
<input type="text" name="myCars[1].name">
</form:form>
and, submit. The result of this test is that #ModelAttribue Car car still remains 3rd element in List myCars. I expected to remain 2 Car elements, but it wasn't. I think it remained in session. And it was overwritten new form data to #ModelAttribute Car car object, but last 3rd element wasn't. My test shows that if form elements increase dynamically, binding object using #ModelAttribute have them. But though decreased dynamically, binding object still have them. I hope that Car car object have accurate number of form inputs. What should I do?
Thanks in advance.

Resources