I have a SpringBoot app. with this thymelaf template, that works fine when submitting:
<div class="form-group required-control">
<label for="gre">GRE</label>
<input id="gre" type="checkbox" name="gre" th:checked="*{gre}" th:onclick="submit()" />
</div>
but when I add another checkbox, It always take in account the first one, regardless which one I click
<div class="form-group required-control">
<label for="gre">GRE</label>
<input id="gre" type="checkbox" name="gre" th:checked="*{gre}" th:onclick="submit()" />
<label for="gre2">GRE2</label>
<input id="gre2" type="checkbox" name="gre2" th:checked="*{gre2}" th:onclick="submit()" />
</div>
There is no technical problem here. I think there is a problem with your submit() function, because I created a normal form and tried your same instance, and all selection combinations worked correctly.
I am adding the entity, controller and html files respectively for example.
public class Example {
private boolean gre;
private boolean gre2;
public Example() {
}
// getter/setter ...
}
#Controller
#RequestMapping("/example")
public class ExampleController {
#GetMapping("/create")
public String createExample(Model model) {
model.addAttribute("example", new Example());
return "example-form";
}
#PostMapping("/insert")
public String insertExample(Model model, Example example) {
model.addAttribute("example", example);
return "example-form";
}
}
<!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<body>
<div>
<form action="/example/insert" method="post" th:object="${example}">
<div class="form-group required-control">
<label for="gre">GRE</label>
<input id="gre" type="checkbox" name="gre" th:checked="*{gre}" />
<label for="gre2">GRE 2</label>
<input id="gre2" type="checkbox" name="gre2" th:checked="*{gre2}" />
</div>
<button type="submit">Submit Form</button>
</form>
</div>
</body>
</html>
If you don't want to add an attribute into the Model, you can receive checkbox condition via HttpServletRequest.
#GetMapping("/create")
public String createExample() {
return "example-form";
}
#PostMapping("/insert")
public String insertExample(User user, HttpServletRequest request) {
user.setGre(request.getParameter("gre") != null);
user.setGre2(request.getParameter("gre2") != null);
userServiceImp.updateUser(editedUser); //for example updating user in database
return "/";
}
HTML will be like this:
<form th:action="/insert" method="post">
<div class="form-group required-control">
<label>GRE</label>
<input type="checkbox" name="gre"/>
<label>GRE 2</label>
<input type="checkbox" name="gre2"/>
</div>
<button type="submit">Submit Form</button>
</form>
Related
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 have got two methods that redirect to the same .html file.
First method is method responsible for saving, the second method is for updating.
It has got the same view so I just wanted to move user to the same view.
I have <h1>..</h1> in .html I would like to have title "New Mapping" for adding new mapping and "Update mapping" when we want to update mapping.
These are methods that do all the stuff (redirecting to the .html file)
#RequestMapping(path = "/.../update", method = RequestMethod.GET)
public String updatePage(#RequestParam("...") String ..., Model model) {
String[] tokens = ....split("_");
Template template= class.method(...);
model.addAttribute("template", template);
return "save";
}
#RequestMapping(path = "/.../save")
public String newMappingPage(Model model) {
Template template = new Template();
template.setCostIndex("10");
model.addAttribute("template", template);
return "save";
}
#RequestMapping(path = "/.../save", method = RequestMethod.POST)
public String saveMapping(#ModelAttribute Template template) {
class.method(template);
return "redirect:/main-page";
}
save.hml file
<html>
<head>
<title>Engine</title>
<link rel="stylesheet" th:href="#{/css/file.css}"/>
</head>
<body>
<h1>New/Update mapping</h1>
<form action="save" method="post" th:object="${template}">
<fieldset>
<label for="...">....[min]</label>
<input type="number" id="..." th:field="*{...}" step="0.1" min="0"/>
<label for="...">...</label>
<input type="number" id="...." th:field="*{...}" required="true"/>
<label for="...">....</label>
<input type="text" id="..." th:field="*{...}" maxlength="1024" size="50"/>
<br/>
<br/>
<label for="response">Response</label>
<br/>
<textarea id="response" rows="20" cols="150" th:field="*{...}" required="true"/>
<br/>
<input id="submit" type="submit" class="primary" value="Submit"/>
</fieldset>
</form>
</body>
</html>
You do not need to create two separate methods for add and update as you are storing data into DB from JSP page. use only one /save API.
#PostMapping(path = "/.../{}/save")
public String newMappingPage(Model model) {
Template template = new Template();
template.setCostIndex("10");
model = new Model();
if (model.getId() > 0) {
model = findById(model.getId());
model.addAttribute("heading", "Update Mapping");
} else {
model.addAttribute("heading", "New Mapping");
}
//Call method to store data from jsp file
return "save";
}
In JSP :
<html>
<head>
<title>Engine</title>
<link rel="stylesheet" th:href="#{/css/file.css}"/>
</head>
<body>
<h1>${heading}</h1>
<form action="save" method="post" th:object="${template}">
<fieldset>
<label for="...">....[min]</label>
<input type="number" id="..." th:field="*{...}" step="0.1" min="0"/>
<label for="...">...</label>
<input type="number" id="...." th:field="*{...}" required="true"/>
<label for="...">....</label>
<input type="text" id="..." th:field="*{...}" maxlength="1024" size="50"/>
<br/>
<br/>
<label for="response">Response</label>
<br/>
<textarea id="response" rows="20" cols="150" th:field="*{...}" required="true"/>
<br/>
<input id="submit" type="submit" class="primary" value="Submit"/>
</fieldset>
</form>
</body>
</html>
Update your method like this:
#PostMapping(path = "/.../{}/save")
public ModelAndView save(Model model) {
ModelAndView obj = new ModelAndView("save");
model = new Model();
if (model.getId() > 0) {
model = findById(model.getId());
obj .addAttribute("heading", "Update Mapping");
} else {
obj .addAttribute("heading", "New Mapping");
}
//Call method to store data from jsp file
return obj;
}
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'm sort-of shocked that I can't find an example of how to do this. Every time I google it, I get info on how to post a collection of objects, or other unrelated stuff. The thymeleaf documentation (what I can find of it) seems to not explain much either, like there is a lot of assumed knowledge.
Getting back to my question, I just want to post a single object (bean) from a form. I would like my controller mapping method to bind to this "pojo" bean and not to a bunch of strings/integers.
The only thing that I have found that comes close is stuff on StackOverflow where half of the code is in the question, the other half is in the answer, and there are always a few comments from people saying it didn't work for them.
Can anyone offer any relief here with a plain old boring example?
Can find the below code snippet might helpful for you.
Controller GET/POST mapping:
#RequestMapping(value = "/registration", method = RequestMethod.GET)
public String registartionPage(Model model) {
Registration registration = new Registration();
model.addAttribute("registration", registration);
return "registarion/registarion";
}
#RequestMapping(value = "/user/new-user-registrn", method = RequestMethod.POST)
public String newUserRegistrn(Model model, #ModelAttribute("registration")
Registration registration, RedirectAttributes redirectAttributes) {
try {
StarUser user = starSecurityService.findSysUserName(registration.getUserName());
if (user != null) {
throw new Exception("User Already Exist. Please try with different User Name");
}
user = (StarUser) starUtilService.save(setStarUser(registration));
model.addAttribute("registration", registration);
if (user != null) {
redirectAttributes.addAttribute("starMessage",
"Your Account is successfully created !! Login to Access the Application");
return "redirect:/";
}
} catch (Exception e) {
model.addAttribute(STAR_MESSAGE, e.getMessage());
}
return "registarion/registarion";
}
Thymeleaf Content:
<form class="form-horizontal col-sm-12" method="POST" th:action="#{/user/new-user-registrn}" th:object="${registration}">
<div class="row">
<div class="form-group col-md-12">
<div class="star-reg-header">New User Registration</div>
</div>
<div class="star-reg-body">
<div class="form-group col-sm-4">
<label class="required">First Name: </label>
<input type="text" class="form-control required" th:field="*{firstName}" required="required" />
</div>
<div class="form-group col-sm-4">
<label class="required">Last Name: </label>
<input type="text" class="form-control" th:field="*{lastName}" required="required" />
</div>
<div class="form-group col-sm-4">
<label class="required">User Name: </label>
<input type="text" class="form-control" th:field="*{userName}" required="required" />
</div>
<div class="form-group col-sm-4">
<label class="required">Password: </label>
<input type="password" class="form-control" th:field="*{password}" required="required" />
</div>
<div class="form-group col-sm-4">
<label class="required">Email: </label>
<input type="text" class="form-control" th:field="*{email}" required="required" />
</div>
</div>
</div>
<div class="form-group col-md-12">
<label class="col-sm-2"></label>
<div class="col-sm-10">
<button type="submit" class="btn btn-info">Submit</button>
</div>
</div>
Java Bean class
public class Registration {
protected String firstName;
protected String lastName;
protected String userName;
protected String password;
protected String email;
//Setter and Getter
}
Use #ModelAttribute annotation in the parameter.
Something like this.
#RequestMapping(value = "/someurl", method = RequestMethod.POST)
public String savePojo(#ModelAttribute PojoClass pojo, Model model) {
//Code
}
Edit: This answer has very good info on this.
What is #ModelAttribute in Spring MVC?
Hi guys hope you can help me, because i cant get further at the moment
I have my Controller.
#RequestMapping(value="/kundenseite", method= RequestMethod.GET)
public String kundenLogin(ModelMap model) {
if(kundeComponent.getKunde() != null) {
List<Restaurant> restaurants = restaurantService.alleRestaurants();
model.addAttribute("restaurants", restaurants);
return "kundenseite";
}else {
return "redirect:/kunde/login";
}
}
#RequestMapping(value="/kundenseite", method= RequestMethod.POST)
public String kundenLoginAnswer(ModelMap model, #ModelAttribute Restaurant restaurant) {
System.out.println(restaurant.toString());
return "kundenseite";
And my jsp file
<%# include file="common/header.jspf" %>
<div class="jumbotron text-center">
<h1>MiMiMi Lieferservice</h1>
<p>Der schnellste Lieferservice von Passpick</p>
</div>
<div style="margin-right:auto; margin-left:auto; width: 33%">
<h2 style="text-align: center">Restaurant wählen</h2>
<div class="well">
<c:forEach items="${restaurants}" var="restaurant">
<form:form modelAttribute="${restaurant}" method="post">
<div style="margin-top: 8px" class=col-sm-4 >${restaurant.name}</div>
<div style="margin-top: 8px" class=col-sm-4 >${restaurant.restaurantTyp}</div>
<button type="submit">Bestellen</button>
</form:form>
<br style="clear:both;" />
</c:forEach>
</div>
</div>
</body>
</html>
If the user presses a button i want to return a restaurant.
But i don't know how to make that happen, my thought was to use a form but i cant get it to send a complete restaurant object back
If there is no solution for this i have to write the id with the button.
You need input hidden inside the form tab as below input hidden:
<input type="hidden" name="name" value="${restaurant.name}">
<input type="hidden" name="restaurantTyp" value="${restaurant.restaurantTyp}">