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>
Related
I have an model object that I send to front end. I populate that object inside the form. What I want to know is that if I can partially populate that object from a different event before user submits his/her form?
Example:
Entity:
public class Participant {
public String username;
public boolean taskCompleted;
}
Thymeleaf Form:
<form th:object="${participant}" th:action="#{/join}" method="post">
<input type="text" th:field="*{username}" >
<button type="submit">Join!</button>
</form>
Before submitting the form, I give users a task, like clicking a button on a different part of the page. If they do it, I want to do something like taskCompleted = true of the same participant object. Is that possible?
Use a hidden input in your form:
<form th:object="${participant}" method="post">
<input type="text" th:field="*{username}" >
<input type="hidden" th:field="*{taskCompleted}" />
<button type="submit">Join!</button>
</form>
When the user clicks a button, use JavaScript to set the value of the hidden input to true.
<!-- This button flips the value of taskCompleted to true -->
<button onclick="document.getElementById('taskCompleted').value = 'true';">Do the task first!</button>
I'm using Spring+Thymeleaf to see and modify the users in a database. I would like to set the input fields to the actual values of an original user but I've tried with different styles and it doesn't work.
With the present configuration I can update information of users and see the id of original user (it's not in a input field) but I can't show the actual configuration in input field as default.
CONTROLLER:
#GetMapping(value = {"/", ""})
public String subusersPage(HttpSession session, Model model) {
String idUser = BaseController.getLoggedUser(session);
UserDTO userDTO = userService.getUserById(idUser);
model.addAttribute("subusersDTO", userService.getSubusersDTO(userDTO.getSubusers()));
model.addAttribute("populations", userDTO.getPopulations());
model.addAttribute("configurations", userDTO.getConfigurations());
model.addAttribute("attributes", userDTO.getAttributes());
model.addAttribute("subuserDTO", new SubuserDTO());
return "subusers";
}
HTML:
<th:block th:each="subuserDTO_original : ${subusersDTO}">
<hr>
<form action="#" th:action="#{/subusers/__${subuserDTO_original.id}__}" th:object="${subuserDTO}" method="post">
<div>
<p th:text="${'Id: ' + subuserDTO_original.id}"></p>
<p>Name: <input type="text" th:field="*{name}" th:name="name" th:value="${subuserDTO_original.name}"/></p>
<p>Population: <input type="text" th:field="*{population}" th:name="population" th:value="${subuserDTO_original.population}"/></p>
<p>Configuration: <input type="text" th:field="*{configuration}" th:name="configuration" th:value="${subuserDTO_original.configuration}"/></p>
<p>Attributes: <input type="text" th:field="*{attributes}" th:name="attributes" th:value="${subuserDTO_original.attributes}"/></p>
<p>
<button type="submit" th:name="action" th:value="update">Update</button>
<button type="submit" th:name="action" th:value="delete">Delete</button>
<button type="reset" th:name="action" th:value="clear">Clear</button>
</p>
</div>
</form>
<form action="#" th:action="#{/subusers/__${subuserDTO_original.id}__}" method="get">
<button type="submit">Default</button>
</form>
</th:block>
Any help will be very appreciated, thank you!
If you want to edit an existing user, then your th:object (which is ${subuserDTO} in this case) needs to be populated with the values of the original user. This is because when you use the attribute th:field="*{name}", it actually overwrites the name, id, and value of the html tag (which is why th:value="${subuserDTO_original.name}" isn't working.
Two other options you could do:
You could also set name="name" and use th:value instead.
Or another option, you could use ${subuserDTO_original} as your th:object.
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.
I have the following content in my HTML which is using Thymeleaf
<form action="#" th:action="#{/shutDown}" th:object="${ddata}" method="post">
<span>Domain</span>
<span th:text="${domain}" th:field="*{domain}">domain</span>
<input type="Submit" value="close" />
</form>
And I have the following in my Controller which is using Sprint Boot
#RequestMapping(value = "/shutDown", method = RequestMethod.POST)
public ModelAndView shutDownPage(ModelAndView modelAndView, Authentication authentication,
#ModelAttribute("ddata") DInputBean dInputBean) {
String domain = dInputBean.getdomain();
return modelAndView;
}
I'm hoping I'd get value of domain from the HTML in the Controller but it's always null. DInputBean has getters and setters for "domain" field.
The th:field attribute can be used on <input>, <select>, or, <textarea>.
A solution you could possibly replacing you second <span> with a hidden input element.
<form action="#" th:action="#{/shutDown}" th:object="${ddata}" method="post">
<span>Domain</span>
<input type="hidden" th:field="*{domain}" th:value="${domain}" />
<input type="Submit" value="close" />
</form>
If you wanted to keep the second div, just place the <input type="hidden"> inside the second <span> and remove the th:field attribute from the second <span>.
Edit:
If you wanted to add the value of domain in a span.
<form action="#" th:action="#{/shutDown}" th:object="${ddata}" method="post">
<span>Domain</span>
<span th:text="${domain}">domain<span>
<input type="hidden" th:field="*{domain}" th:value="${domain}" />
<input type="Submit" value="close" />
</form>
http://www.thymeleaf.org/doc/tutorials/3.0/thymeleafspring.html#inputs
An option is to use a read-only input field:
<input type="text" th:field="*{domain}" th:value="${domain}" readonly="readonly"/>
This both displays the value and sends it on submit.
The key is to add the value of the domain variable to the form:
#GetMapping("/shutDownPage")
public String shutDownPage(Model model) {
model.addAttribute("ddata" new Ddata()); //or however you create your bean
String username = ... //however you get your username
String domain = myRepositoryService.findDomainByUsername(username);
model.addAttribute("domain", domain);
return "shutDownPage";
}
Include an HTML page in the action so that when you open the HTML page in a browser without a server/container, the button will still appear to work:
<form action="confirmationPage.html" th:action="#{/shutDown}" th:object="${ddata}" method="post">
<!-- You can benefit from using a conditional expression -->
<span th:text="${domain != null ? domain : 'No domain supplied'}">[domain]</span>
<input type="hidden" th:field="*{domain}" th:value="${domain}"/>
<input type="Submit" value="close"/>
</form>
And your post method:
#PostMapping("/shutDown") //use shorthand
public String shutDownPagePost(#ModelAttribute("ddata") DInputBean dInputBean {
String domain = dInputBean.getDomain();
//do whatever with it
return "confirmationPage";
}
I have a small problem. I'm passing a id from one view to another.
I do it like this:
#Html.Partial("DetailViews/_Parameters", Model.Parameters, new ViewDataDictionary { { "data-resourceId", Model.Id } })
I use this id for a hidden field in a form on the partial view. like this:
<form id="formAddNewParameter" action"#" title="Add new Parameter">
<input type="hidden" name="resourceId" id="resourceId" class="required" rel="0" value=#ViewData["data-resourceId"]/>
</form>
The ID is passed as it should. BUT there is always a "/" at the end...
Anyone know where this "/" comes from.
You are missing the qutation marks "" around the value tag's value
<form id="formAddNewParameter" action"#" title="Add new Parameter">
<input type="hidden" name="resourceId"
id="resourceId" class="required" rel="0"
value="#(ViewData["data-resourceId"])" />
</form>
And I guess the tag closing / somehow mixed into the value tag.