In my thymeleaf template I add a hidden field for a field on my form object:
<form action="#" th:action="#{/admin/endpoint}" th:object="${monkey}" method="post" class="form-horizontal" role="form">
<input type="hidden" th:field="*{id}" />
<input type="hidden" th:field="*{banana}" />
...
</form>
Created html output:
<input type="hidden" id="id" name="id" value="55">
<input type="hidden" id="banana" name="banana" value="3">
Posting this form through a web browser works as expected, but
when I try to test this with MockMvc only the id field gets set:
mvc.perform(post("/endpoint")
.param("id", String.valueOf(monkey.getId()))
.param("banana", String.valueOf(monkey.getBanana().getId())))
In my controller I let Spring transform the form for me:
#RequestMapping(value = { "/admin/endpoint" }, method = RequestMethod.POST)
public String updateMonkey(Model model, #Valid Monkey monkey, BindingResult br) {
System.out.println(monkey.getId()) // -> 55
System.out.println(monkey.getBanana()) // -> null
...
}
What do I have to change so the field "banana" gets properly initialized from the id in my test?
Related
I familiarize myself with Thymeleaf.
I am trying to get data from a POST-mapping in the controller.
But I got null variables when I call employee.getName().
I looked a lot online but can't find a solution.
My controller class
#GetMapping
public String getEmployees(Model model) {
model.addAttribute("newEmployee", new Employee());
return "employees";
}
#PostMapping
public String addEmployee(#ModelAttribute("newEmployee") Employee employee) {
System.out.println(employee); // return object
System.out.println(employee.getFirstName()); // return null
return "employees";
}
HTML form with Thymeleaf
<div class="modal-body">
<form th:action="#{/employees}" th:object="${newEmployee}" method="post">
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label class="col-form-label">First Name <span class="text-danger">*</span></label>
<input th:field="*{firstName}" class="form-control" type="text">
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label class="col-form-label">Last Name</label>
<input th:field="*{lastName}" class="form-control" type="text">
</div>
</div>
See tutorials:
Wim Deblauwe: Form handling with Thymeleaf
Baeldung: Binding a List in Thymeleaf
#GetMapping("/all")
public String showAll(Model model) {
model.addAttribute("employees", employeeService.findAll());
return "employees/all";
}
#GetMapping("/add")
public String createForm(Model model) {
model.addAttribute("newEmployee", new Employee()); // the form-data object as blank employee to be filled
return "employees/form"; // the page containing the form
}
#PostMapping
public String addEmployee(#ModelAttribute("newEmployee") Employee employee) {
System.out.println(employee); // return object
System.out.println(employee.getFirstName()); // return null if either not set in HTML-form or not mapped from HTML-form to POST correctly
// save new employee or add to a repository
employeeService.save(newEmployee);
model.addAttribute("employees", employeeService.findAll());
return "redirect:/employees/all"; // use a redirect
}
Client-Server interaction:
First in your browser you should navigate to the endpoint adding the form-data-object, i.e. GET /employees/add.
Then the form-page should load and you will have a blank object newEmployee to bind all the input-fields to for submitting.
After submitting the form via the submit-click, a POST /employees is sent. The server/controller should receive the form-data as model-attribute in employee parameter and can save it.
The controller-method redirects back to the list-endpoint (same as navigating in browser to) GET /employees/all
<h1>Create employee</h1>
<form th:object="${newEmployee}"
th:action="#{/employees}"
method="post">
<input type="text" name="firstName" id="firstName" th:field="*{firstName}" />
<input type="text" name="lastName" id="lastName" th:field="*{lastName}" />
<button type="submit">Submit new employee</button>
</form>
The th:object attribute refers to the key under which we put our Employee instance in the model (newEmployee in this example). The th:action has the URL for the #PostMapping method. Finally, the method attribute is set to "post" since we want to use the HTTP POST method.
Using th:field=*{…}, we can setup a two-way binding between the HTML input and the field in our form data object.
I have an html page (format - FTL) in which I am trying to send data to a controller method. I am only trying to print the items that the user typed, nothing fancy for the beginning. I get the error - Required String parameter 'user_id' is not present
I work with spring mvc and freemarker.
This is the signup.ftl file -
<form method="POST", action="GET">
<div class="container">
<h1>Register</h1>
<p>Please fill in this form to create an account.</p>
<hr>
<label for="email" id="email"><b>Email</b></label>
<input type="text" placeholder="Enter Email" name="email" required>
<label for="password" id="password"><b>Password</b></label>
<input type="password" placeholder="Enter Password" name="password" required>
<label for="user_id" id="user_id"><b>User ID</b></label>
<input type="text" placeholder="user_id" name="user_id" required>
<hr>
<p>By creating an account you agree to our Terms & Privacy.</p>
<button type="submit" class="registerbtn">Register</button>
</div>
<div class="container signin">
<p>Already have an account? Sign in.</p>
</div>
</form>
</body>
</html>
This is the controller -
#RequestMapping(value = "/signup", method = RequestMethod.GET)
public String signup(#RequestParam("user_id")String user_id, #RequestParam("password")String password, #RequestParam("email")String email, Model model) {
System.out.println("coming in controller" + user_id + " " + password);
return "signup";
}
You are passing wrong action method and value.
You have to match the controller method signature which is
#RequestMapping(value = "/signup", method = RequestMethod.GET)
Change form tag to below line of code.
<form method="GET", action="signup">
I'm having issues with the above code recognizing the 'defaultpagination' variable. It keeps throwing the 'Required String parameter 'defaultpagination' is not present' message on the user interface. This is part of an edit screen showing a configurable setting.
The controller method is below.
#RequestMapping(value = "/update", method = RequestMethod.POST)
public ModelAndView updateSetting(
#RequestParam("defaultpagination") String defaultPagination,
#RequestParam("id") long id) {
Setting setting = settingService.getOne(id);
setting.setDefaultPagination(Integer.parseInt(defaultPagination));
settingService.saveSetting(setting);
return new ModelAndView("redirect:/settings/setting-listing");
}
The thymleaf html can be seen below.
<form role="form" data-toggle="validator" name="createSetting" enctype="multipart/form-data" method="post" th:object="${setting}" action="/settings/update">
<div class="form-group">
<label for="defaultpagination">Default Pagination</label>
<input class="form-control" name="defaultpagination" type="number" th:field="${setting.defaultPagination}" placeholder="Enter default pagination" required="required" data-error="Pagination is required (maximum cannot exceed 100)" />
<div class="help-block with-errors"></div>
</div>
<input type="hidden" th:rows="1" class="form-control" id="id" name="id" th:value="${setting.id}"/>
<br />
<button type="submit" class="btn btn-default">Submit Button</button>
<br />
<br />
<br />
</form>
What's interesting is that I can change the 'input' tag to a textarea tag and everything would work as normal (the defaultpagination gets recognized). However, I want to use the input for validation. In this case the input needs to be a number. In similar cases, I will need a phone number and email. Has anyone faced this same problem regarding the input/textarea tag in thymeleaf?
one solution would be to change the String defaultPagination in the controller to Integer (if you expect only integer as defaultpagination)
ie
#RequestMapping(value = "/update", method = RequestMethod.POST)
public ModelAndView updateSetting(
#RequestParam("defaultpagination") Integer defaultPagination,
#RequestParam("id") long id) {
Another solution is to use the pattern attribute of the input tag (permit only numbers not decimal points)
<input class="form-control" name="defaultpagination" type="text"
pattern="\d+" th:field="${setting.defaultPagination}" placeholder="Enter default
pagination" required="required" data-error="Pagination is required (maximum cannot exceed 100)" />
Let me know if these worked for you
I have a page with two forms, and want to add object from first form when submitting second one. Basically it looks like this:
First form:
<form action="#" method="POST" enctype="multipart/form-data" th:action="#{/foo}" th:object="${prop1}" id="form1">
<input type="file" name="file" class="form-control"/>
<input type="text" th:value="${prop1.taskSheetName}" name="taskSheetName"/>
<input type="number" th:value="${prop1.descriptionColumnPosition}" name="descriptionColumnPosition"/>
</form>
Second form:
<form th:if="${resourceId}" action="#" method=" th:object="${prop2}" id="prop2" th:action="#{/foo/{id}(id=${resourceId})}">
<input type="url" th:value="${prop2.url}" name="url"/>
<input type="text" th:value="${prop2.username}" name="username"/>
<input type="password" th:value="${prop2.password}" name="password"/>
</form>
And controller methods:
#RequestMapping(value = "/foo", method = POST)
public String uploadFile(#RequestParam("file") MultipartFile file, final ExcelProperties properties, final Model model) {
//some logic here
}
#RequestMapping(value = "/process/{id}", method = POST)
public String processResource(#PathVariable("id") String id, final Prop2 prop2, final Prop1 prop1, final Model model) {
}
And I need to pass the values from first form values to second method with second form values, but it passes empty form object. I tried to add
<div th:with="p1=${prop1}">
since I know that this data is present in page, but it didn't help.
If this even possible or should I just give up and write custom submit handler in javascript?
According to MDN, it's impossible to attach 1 input into 2 forms,
You need to do some work with JavaScript.
Hello I'm tryin to developpe a page that can delete users but when I click on submit I have an error Etat HTTP 400 - La requête envoyée par le client était syntaxiquement incorrecte.
Jsp file
</div>
<form method="POST" action="Users">
User ID
<input type="text" name="idUser" /><br><br>
<input type="submit" name="Supprimer" value="Supprimer"/>
</form>
Controller
#RequestMapping(value = "/Users")
public String goUsers(Model model)
{
model.addAttribute("AllUsers", UserS.getAllUsers());
return "Users";
}
#RequestMapping(value = "/Users", method = RequestMethod.POST)
public String goUsers(#ModelAttribute User user,BindingResult result,#RequestParam int id, Map<String, Object> model)
{
UserS.deleteUser(id);
return "Users";
}
thank you
Your controller wrong. You expect oen User and one param with name id but you send one param with name idUser.
Eliminate ModelAttribute and force de name of RequestParam:
#RequestMapping(value = "/Users", method = RequestMethod.POST)
public String goUsers(BindingResult result,#RequestParam(name="idUser") int id, Map<String, Object> model)
{
UserS.deleteUser(id);
return "Users";
}
1.first you need to add modelattribute to your form like this :
Notice how i am using spring forms. You can use them by adding
<%# taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
before DOCTYPE html>
Then you need to add hidden path to attribute "id" so when you controller gets the request you will know which user you will need to delete or edit.
This is example form :
`<form:form method="POST" modelAttribute="User" action="Users">
<form:hidden path="id"/>
<div class="form-group">
<label for="usernameId">Username</label>
<form:input path="username" id="usernameId" class="form-control" />
<form:errors path="username" style="color:red;"></form:errors>
</div>
<div class="form-group">
<label for="fullNameId">Full Name</label>
<form:input path="firstLastName" id="firstLastName" class="form-control"/>
<form:errors path="firstLastName" style="color:red;"></form:errors>
</div>
<div class="form-group">
<label for="passwordId">Password</label>
<form:password path="password" id="passwordId" class="form-control"/>
<form:errors path="password" style="color:red;"></form:errors>
</div>
<div class="form-group">
<label for="emailId">Email</label>
<form:input path="email" id="emailId" class="form-control"/>
<form:errors path="email" style="color:red;"></form:errors>
</div>
<input type="submit" class="btn btn-default" value="Register"/>
</form:form>`
finally you will add to your controller class.
#ModelAttribute("User")
public User getUser(){
return new User();
}
Then you will need to adjust your controller like this :
#RequestMapping(value="/Users", method=RequestMethod.POST)
public String deleteUser(User user){
getRegisterService().deleteUser(user.getId());
return "home";
}
Note : You will have to create class = User : with id attribute(and all others you need). You will also need to create a method for deleting user in your service and repository layer.
P.S. User user in your deleteUser method is actually the same user you created with #modelAttribute annotation.
If you have any additional questions feel free to ask!
I have given you almost exact form i use for register/editing or deleting Users. When you submit form, everything will be saved into object User with annotation #modelAttribute. Hidden id field is crucial here. When you have id, which is primary key you can just create method in repository (something like this)
public void deleteUser(UserJPA userJPA){
getEntityManager().remove(UserJPA);
}
Hope you find this post helpful.