I can't send parameters from view to control using Spring thymeleaf. This is my controller:
#GetMapping(value="/adminP")
public String adminParameter(
#RequestParam(value = "p", required = false) String p,
Model model) {
model.addAttribute("p", p);
System.out.println("The parameter is " + p);
return "adminPage";
}
And this is the form (I'm using a bootstrap modal):
<div id="modalBody" class="modal-body">
<form th:action="#{/adminP}" method="get">
<input type="text" th:name="p">
</div>
<div class="modal-footer">
<button type="submit" th:name="action" class="btn btn-default" data-dismiss="modal">Confirm</button>
</form>
</div>
When I send the form, the console doesn't print.
Do you know where's the problem?
Thank you all
Related
Using #ModelAttribute I am able to post form-data to my backend without issue, however when I try to include a multipart file the server returns a 500 error. There are no console warnings or stack traces thrown, and the POST request endpoint is never hit according to my debugger.
I've tried working backwards, and replacing the MultiPartFile with just a String and changing the file attribute in the HTML to text, and it works just find sending Strings and ints to the back end, but when I add the file type back in and switch the model to MultipartFile, it breaks...
The html form fragment, the submit button triggers the POST request to /new:
<form method="POST" enctype="multipart/form-data" th:action="#{/release/new}" class="mx-auto w-50" th:object="${package}">
<th:block th:include="fragment/error-message.html"></th:block>
<fieldset>
<legend>Release Package Information</legend>
<div class="row">
<div class="col-sm-6 mb-3">
<label>Release Package ID</label>
<input type="text" class="form-control" placeholder="Enter the release package ID" th:field="*{releasePackageId}">
</div>
</div>
<div class="row">
<div class="col-sm-12 mb-3">
<label>Nomenclature</label>
<input type="text" class="form-control" placeholder="Enter the part nomenclature" th:field="*{nomenclature}">
</div>
</div>
<div class="row">
<div class="col-sm-12 mb-3">
<label>File</label>
<input type="file" class="form-control" placeholder="Select the part to upload" th:field="*{file}">
</div>
</div>
</fieldset>
<div class="row">
<div class="col-sm-6">
<a th:href="#{/release}" class="btn btn-outline-secondary w-100">
Back
</a>
</div>
<div class="col-sm-6">
<button type="submit" class="btn btn-outline-success w-100">
Submit
</button>
</div>
</div>
</form>
And here are the controller endpoints for /release/new:
#GetMapping("/new")
public ModelAndView showCreateReleasePackageForm()
{
return new ModelAndView("new-release").addObject("package", new CreateReleasePackageDTO());
}
#PostMapping("/new")
public String createReleasePackage(#ModelAttribute("package") CreateReleasePackageDTO releasePackageDTO, BindingResult result, RedirectAttributes attributes)
{
if (result.hasErrors())
{
return "new-release";
}
String response = "a response";
System.out.println(releasePackageDTO.getReleasePackageId() + releasePackageDTO.getNomenclature() + releasePackageDTO.getFile());
// TODO: Exception handling
// try
// {
// response = this.fileService.save(ReleasePackageMapper.toEntity(releasePackageDTO));
// } catch (JsonProcessingException e)
// {
// response = e.getMessage();
// e.printStackTrace();
// }
attributes.addFlashAttribute("message", response);
return "redirect:/release";
}
Here is the DTO, the model object I am calling "package":
#Getter
#Setter
public class CreateReleasePackageDTO
{
#NotNull(message = "{NotNull.releasePackageId}")
private int releasePackageId;
#NotEmpty(message = "{NotEmpty.nomenclature}")
private String nomenclature;
#NotEmpty(message = "{NotEmpty.multipartFile}")
private MultipartFile file;
}
I'm trying to implement a login form in a Spring boot application. It has an email and a password field. The email field failed to get user input, here is the form:
<form th:action="#{/login}" method="get" th:object="${loginForm}" style="max-width: 600px; margin: 0 auto;">
<div class="m-3">
<div class="form-group row">
<label class="col-4 col-form-label">E-mail: </label>
<div class="col-8">
<input type="text" th:field="*{email}" name="q" class="form-control" required />
</div>
</div>
<div class="form-group row">
<label class="col-4 col-form-label">Password: </label>
<div class="col-8">
<input type="password" th:field="*{password}" class="form-control" required/>
</div>
</div>
<div>
<button type="submit" class="btn btn-primary">Log in</button>
</div>
</div>
</form>
Here is the controller:
#GetMapping("login")
public ModelAndView login(Model model, #RequestParam(name = "q", required = false) Optional<String> email) {
Optional<UserDto> aUser;
System.out.println(email);
if (email.isPresent()) {
aUser = userService.getAUserByEmail(email.get());
model.addAttribute("user", aUser);
var mv = new ModelAndView("user/user-list", model.asMap());
return mv;
} else {
model.addAttribute("loginForm", new LoginForm());
return new ModelAndView("/login/login-form", model.asMap());
}
}
I thought the #RequestParam(name = "q") and name="q" in html would do the job, but I always get Optional.empty for email. Any idea what's wrong here?
UPDATE:
From the answers I changed controller to this:
#GetMapping("login")
public ModelAndView login(Model model, LoginForm loginForm) {
Optional<UserDto> aUser;
if (loginForm.getEmail() != null) {
aUser = userService.getAUserByEmail(loginForm.getEmail());
model.addAttribute("user", aUser);
var mv = new ModelAndView("user/user-list", model.asMap());
return mv;
} else {
model.addAttribute("loginForm", new LoginForm());
return new ModelAndView("/login/login-form", model.asMap());
}
}
login-form.html to this:
<form th:action="#{/login}" method="get" th:object="${loginForm}" style="max-width: 600px; margin: 0 auto;">
<div class="m-3">
<div class="form-group row">
<label class="col-4 col-form-label">E-mail: </label>
<div class="col-8">
<input type="text" th:field="*{email}" class="form-control" required />
</div>
</div>
<div class="form-group row">
<label class="col-4 col-form-label">Password: </label>
<div class="col-8">
<input type="password" th:field="*{password}" class="form-control" required/>
</div>
</div>
<div>
<button type="submit" class="btn btn-primary">Log in</button>
</div>
</div>
</form>
I also have LoginForm.java like this
#Data
#AllArgsConstructor
#NoArgsConstructor
public class LoginForm {
private String email;
private String password;
}
but still not getting user email field input?
The way you have set up your form, it's mapping the value of your email input field to the property email (that's what th:field="*{email}" means) of an object called loginForm (that's what th:object="${loginForm}" means). Neither of these seem to be used or even exist in your login() method. You need to either change what you use in your controller to match what you have in your Thymeleaf template, or change your Thymeleaf template to actually reference what you are using in your controller.
The problem in your code is located under th:object="${loginForm}"
With this you inform spring to bind the data sent from the form into an object named loginForm.
So Spring actually expects the controller to be
#GetMapping("login")
public ModelAndView login(Model model, LoginForm loginForm) {
....
and inside LoginForm a field named email will contain the value sent from the form, as you have declared with <input type="text" th:field="*{email}" .... >
If you don't want the data to be bound into an object from Spring Mvc then
remove the th:object="${loginForm}"
use the
<input type="text" th:name="q" class="form-control" required />
and then the controller will receive the sent value as a query parameter
#GetMapping("login")
public ModelAndView login(Model model, #RequestParam(name =
"q", required = false) Optional<String> email) {
I want to use a form without an object. How to display errors?
Controller:
#PostMapping(value="/submit")
public String doSubmit(#RequestParam("myParameter") String param, BindingResult bindingResult) {
bindingResult.rejectValue("myParameter", "Oh nooo!!!!");
return "html";
}
HTML:
<form th:action = "#{/submit}" method="post">
<label for="myParameter" class="form-label">My Parameter</label>
<input name="myParameter" class="form-control" type="text"/>
<span class="text-danger" th:if="${#fields.hasErrors('myParameter')}" th:errors="myParameter">Error</span>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
th:if="${#fields.hasErrors('myParameter')}" th:errors="myParameter" throws errors, cause "myParameter" is not known.
How to display the error, without using th:object in <form>
I did it with the help of this question Thymeleaf: display global errors by error code
#PostMapping(value="/submit")
public String doSubmit(#RequestParam("myParameter") String param, BindingResult bindingResult) {
bindingResult.reject("myParameter", "myParameter");
return "html";
}
Important: myParameter must not be a key of a message source!
<form th:action="#{/submit}" method="post">
<label for="myParameter" class="form-label">My Parameter</label>
<input name="myParameter" class="form-control" type="text"/>
<span class="text-danger" th:if="${#lists.contains(#fields.globalErrors(), "myParameter")}" th:text="An Error happened">Error</span>
<button type="submit" class="btn btn-primary">Submit</button>
Important: Use " to indicate the string. th:text? may contain a message key like th:text="#{error.code1}"`.
i'm beginner with Thymeleaf, but i want know how to call a method in HTML with Thymeleaf. I'm using Spring Boot with Spring MVC.
I want create a Button with a name like "Edit" and the user will edit the post of the blog, but if i want do that i have to know what's the ID from object Postagem.
My current code HTML: (blog.html)
<div th:each="postagem : ${postagens}">
<div class="blog-post">
<h2 class="blog-post-title" th:text="${postagem.titulo}"></h2>
<p class="blog-post-meta">25 de dezembro de 2019 publicado por Vitor</p>
<p th:text="${postagem.texto}"></p>
<form action="#" th:action="#{/blog}" th:object="${postagem}" method="post">
<button type="submit" class="btn btn-link" th:field="*{id}">Editar</button>
</form>
</div>
<!-- /.blog-post -->
</div>
My current method in Java: (PostagemController.java)
#PostMapping("/blog")
public String edit(Postagem postagem) {
for(Postagem post : postagens.findAll()) {
if(post.getId() == postagem.getId()) {
ModelAndView modelAndView = new ModelAndView("painel");
modelAndView.addObject("postagemEdit", post);
System.out.println("Id: " + post.getId());
System.out.println("Título: " + post.getTitulo());
System.out.println("Autor: " + post.getAutor());
System.out.println("Texto: " + post.getTexto());
break;
}
}
return "redirect:/painel";
}
My current code on "painel.html" where is my form that I want set the information
<form method="post" th:object="${postagemEdit}" th:action="#{/painel}" style="margin: 20px 0">
<div class="form-group">
<input type="text" class="form-control" placeholder="Título" th:field="*{titulo}" /> <br>
<input type="text" class="form-control" placeholder="Spoiler do artigo" th:field="*{spoiler}" /><br>
<input type="text" class="form-control" placeholder="Autor" th:field="*{autor}" /> <br>
<textarea id="mytextarea" th:field="*{texto}"></textarea> <br>
<button type="submit" class="btn btn-primary">Publicar</button>
</div>
</form>
It appears that you have not given the id a value in the html code. The default value for int in Java is 0 and that is possibly the reason why. Try to use 1 instead of *{id}.
If you are retrieving the blog post id and post content from the database which should be so then this problem will be solved.
issues
No name
Value not set
solution 1
<form action="#" th:action="#{/blog}" th:object="${postagem}" method="post">
<input type="hidden" name="id" class="btn btn-link" th:value="*{id}" />
<button type=submit class="btn btn-link">Editar</button>
</form>
solution 2
<form action="#" th:action="#{/blog}" th:object="${postagem}" method="post">
<button name="id" type=submit class="btn btn-link" th:value="*{id}">Editar</button>
</form>
solution 3
function myFunction(id) {
var f = document.createElement("form")
f.style.display="none"
f.action="/action_page.php"
f.method="get"
var inp = document.createElement("input");
inp.value=id
inp.name="id"
f.appendChild(inp);
document.body.appendChild(f);
f.submit();
}
<button type=submit class="btn btn-link" th:data-id="*{id}" onclick='myFunction(this.getAttribute("data-id"))'>Editar</button>
Following is the working code that i used in the html template to call java class function
<small th:text="${T(com.sample.util.UIclass).textContent(instr)}"> </small>
And below is the java class for the method :
package com.sample.util;
import com.sample.models.Instr;
public class UIclass {
public static String textContent(Instr instr)
{
return "Hello";
}
}
In case if you need to access same in javascript following is the code
let d = [[${T(com.sample.UIclass).textContent(instr)}]];
console.log(d);
I am trying to retrieve object on my controller that mapped to my POJO
My POJO looks like this
public interface InventoryDetailPOJO {
String getItem_cd();
}
And this is my form
<div class="row d-flex">
<div class="p-3">
<button class="btn btn-block btn-options btn-save">Save</button>
</div>
</div>
<form action="#"
th:action="#{/stock-list/inventory-detail}"
method="post"
th:object="${inventoryDetail}"
class="pt-3 form-inventory-detail">
<div class="form-group row">
<label for="item_cd" class="col-2 col-form-label col-form-label-sm">
<span class="pull-right">Item No</span>
</label>
<div class="col-10">
<input type="text" class="form-control form-control-sm w-25"
th:field="*{item_cd}">
</div>
</div>
</form>
And for my controller
#RequestMapping(value = "/stock-list/inventory-detail", method = RequestMethod.POST)
public ModelAndView InventoryDetailSubmitPage(ModelAndView modelAndView,
#ModelAttribute("inventoryDetail") InventoryDetailPOJO inventoryDetail,
#RequestParam("item_cd") String item_cd) {
System.err.println("InventoryDetail: " + inventoryDetail);
System.err.println("item_cd: " + item_cd);
modelAndView.setViewName("redirect:/stock-list");
return modelAndView;
}
There're no item on inventoryDetail when I tried to log it, but There's a value on item_cd
Remove action="#", like this:
<form th:action="#{/stock-list/inventory-detail}"
method="post"
th:object="${inventoryDetail}"
class="pt-3 form-inventory-detail">