Bind a list of radio buttons with Spring and Thymeleaf - java

my problem is that I need to get the radio buttons that are selected in HTML file and use it in the PostMapping.
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Do Test Excercise</title>
<script language="javascript">
</script>
</head>
<body>
<h1>Do Test Exercise</h1>
<form method="POST">
<span align="left" th:each="question : ${exercise.getQuestions()}">
<p valign="top" th:text="${question.text}">Text</p>
<tr align="left" th:each="solution : ${question.getSolutions()}">
<input width="5%" type="radio" th:name="${question.question_ID}" th:text="${solution.text}"
th:value="${solution.text}"/><BR>
</tr>
</span>
<input type="submit" value="Submit">
</form>
</body>
</html>
However I don't know how to get that values for the radio buttons and save it in a array of String
#GetMapping("doTest/{post}/{exercise}")
public String doTest(Model model, #PathVariable String exercise) {
model.addAttribute("exercise", exercisesDAO.getExerciseByType(exercise, "Test"));
return "exercise/doTestExercise";
}
#PostMapping("doTest/{post}/{exercise}")
public String doTest(#RequestParam(value = "solution") String[] solution, #PathVariable String post, #PathVariable String exercise, RedirectAttributes redirectAttributes) {
exercisesDAO.solve(exercise, solution, "admin", "Test");
redirectAttributes.addAttribute("post", post);
redirectAttributes.addAttribute("exercise", exercise);
return "redirect:/showMark/{post}/{exercise}";
}
Thanks

You need to change the name of your inputs from th:name="${question.question_ID}", to th:name="${'solution['+ question.question_ID + ']'}". After that, you need to change your controller, so that instead of an array of Strings, it will receive a HashMap, where you will get for each id, the chosen solution.
Form
<form method="POST" th:action="#{doTest/${post.id}/${exercise.id}}">
<span align="left" th:each="question : ${exercise.getQuestions()}">
<p valign="top" th:text="${question.text}">Text</p>
<tr align="left" th:each="solution : ${question.getSolutions()}">
<input width="5%" type="radio" th:name="${'solution['+ question.question_ID + ']'}" th:text="${solution.text}" th:value="${solution.text}"/><BR>
</tr>
</span>
<input type="submit" value="Submit">
</form>
Controller
#PostMapping("doTest/{post}/{exercise}")
public String doTest(#RequestParam(value = "solution") HashMap<String, String> solutions, #PathVariable String post, #PathVariable String exercise, RedirectAttributes redirectAttributes) { ... }

Related

Using ftl display list from POST method

Sorry for my english!
I am new to Spring and FTL.
I want to display firstName and lastName using <#list template, but I could not recognize any sequences in my POST method, could some one please explain to me. Again I am a newbie and please don't judge me if I don't understand what I should. I am using CUBA STUDIO 6.8 and IDEA. Also I'm working on this task in portal module
This is how I add firstName and lastName to database using my ftl form and Portal Controller:
#GetMapping("/add")
public String add(Model model){
PersonPojo personPojo = new PersonPojo();
model.addAttribute("personPojo", personPojo);
return "add";
}
#PostMapping("/add")
public String save(Model model, #ModelAttribute("personPojo") PersonPojo personPojo){
String firstName = personPojo.getFirstName();
String lastName = personPojo.getLastName();
PersonPojo newPerson = new PersonPojo(firstName, lastName);
Person standardEntity = metadata.create(Person.class);
standardEntity.setFirtName(newPerson.getFirstName());
standardEntity.setLastName(newPerson.getLastName());
dataManager.commit(standardEntity);
return "redirect:/allPersons";
}
My ftl form:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="" method="post" name="person">
First Name: <input type="text" name="firstName"> <br>
Last Name: <input type="text" name="lastName"> <br>
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}">
<input type="submit" value="Create">
</form></body>
</html>
Thank you!
So, If someone is interested i will post my solution here:
#RequestMapping(value = "/allPersons", method = RequestMethod.GET)
public String getPersons(Model model) {
LoadContext loadJohn = new LoadContext(John.class);
loadJohn.setQueryString("select u from test6$John u");
model.addAttribute("users", dataService.loadList(loadJohn));
return "list";
}
And the ftl should look like this:
The problem i faced next was I did not know I have to check list for null. !"" does that
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>Person List</h3>
Add Person
<br><br>
<div>
<table border="1">
<tr>
<th>First Name</th>
<th>Last Name</th>
</tr>
<#list users as show>
<tr>
<td>${show.firstName!""}</td>
<td>${show.lastName!""}</td>
</tr>
</#list>
</table>
</div>
</body>
</html>
I hope this will help to people like me.
Also, If someone knows how to delete and update data please share.
Thanks!

Thymeleaf: Update Table on Form Submit

I have a view in which I have a Form to create a new Exercise object, and a table to display all exercises. Now I want that the table automatically refreshes with the newly created exercise. Currently it displays the table as empty, until I manually go to localhost:8080/exercise again.
Here's my controller:
#Controller
public class ExerciseController {
#Autowired
private ExerciseService exerciseService;
#Autowired
private ModelMapper modelMapper;
#GetMapping("/exercise")
public String exerciseView(final Model model) {
List<Exercise> exerciseList = exerciseService.getAllExercises();
model.addAttribute("exerciseDTO", new ExerciseDTO());
model.addAttribute("title", "Create an Exercise");
model.addAttribute("exercises", exerciseList);
return "exercise";
}
#PostMapping("/exercise")
public String createExercise(#ModelAttribute final ExerciseDTO exerciseDto) {
final Exercise exercise = this.modelMapper.map(exerciseDto, Exercise.class);
this.exerciseService.createExercise(exercise);
return "exercise";
}
}
And my thymeleaf template:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="template :: head"></head>
<body>
<header th:replace="template :: navbar"></header>
<h1>Form</h1>
<form action="#" th:action="#{/exercise}" th:object="${exerciseDTO}" method="post">
<p>Name: <input type="text" th:field="*{name}" /></p>
<p>Description: <input type="text" th:field="*{description}" /></p>
<p>Exercise type:
<select th:field="*{type}" id="typeSelector">
<option th:each="type : ${T(com.nsterdt.routinierbackend.data.enums.ExerciseType).values()}"
th:value="${type}" th:text="${type.displayName}">
</option>
</select>
</p>
<p id="bpmRow">BPM: <input type="number" th:field="*{bpm}" id="bpmInput" /></p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
<br>
<table>
<tr>
<th>Name</th>
<th>Description</th>
<th>Type</th>
<th>BPM</th>
</tr>
<tr th:each="exercise : ${exercises}">
<td th:text="${exercise.name}"></td>
<td th:text="${exercise.description}"></td>
<td th:text="${exercise.type}"></td>
<td th:text="${exercise.bpm}"></td>
</tr>
</table>
</body>
</html>
Now I thought the createExercise method returning "exercise" would call the exerciseView method and thus calling exerciseService.getAllExercises(). Is there a way to achieve this functionality? Or is there an even better way, without reloading the whole page?
To serve up data without page refreshes you'd need a client side technology like Angular or React. Or plain old javascript. But you can't serve up new data to a page in spring mvc w/o page refreshes.
You can use AJAX to send requests from a client side to a server side and receive an answer without refreshing the page.
Unfortunately I don't have enough time and I can't complete the code but you can do something like this:
function submitItems() {
var contextPath = $("meta[name='ctx']").attr("content");
var exerciseDto = {};
exerciseDto.name = $("#name").val();
exerciseDto.description = $("#description").val();
exerciseDto.typeSelector = $("#typeSelector).val();
exerciseDto.bpmInput = $("#bpmInput").val();
$.ajax({
dataType : "json",
type : "post",
url : contextPath + "/exercise",
data : JSON.stringify(exerciseDto),
cache : false,
contentType : "application/json",
beforeSend : function(xhr) {
xhr.setRequestHeader(header, token);
},
success : function(data) {
console.log(data);
//HERE YOU NEED ACTION TO UPDATE TABLE.
},
error : function(jqXHR, textStatus, errorThrown) {
console.log(jqXHR.responseText);
console.log('getJSON request failed! ' + textStatus);
}
});
}
and then your view must be like this:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="template :: head"></head>
<body>
<header th:replace="template :: navbar"></header>
<h1>Form</h1>
<form onsubmit="submitItems();return false;">
<p>Name: <input id="name" type="text" /></p>
<p>Description: <input id="description" type="text" /></p>
<p>Exercise type:
<select th:field="*{type}" id="typeSelector">
<option th:each="type : ${T(com.nsterdt.routinierbackend.data.enums.ExerciseType).values()}"
th:value="${type}" th:text="${type.displayName}">
</option>
</select>
</p>
<p id="bpmRow">BPM: <input type="number" id="bpmInput" /></p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
<br>
<table>
<tr>
<th>Name</th>
<th>Description</th>
<th>Type</th>
<th>BPM</th>
</tr>
<tr th:each="exercise : ${exercises}">
<td th:text="${exercise.name}"></td>
<td th:text="${exercise.description}"></td>
<td th:text="${exercise.type}"></td>
<td th:text="${exercise.bpm}"></td>
</tr>
</table>
</body>
</html>
Bear in mind that you need to create an JS action that will update the table. There are quite a few ways of doing that (you can push new data to the Datatable or add new content using JS functions).
I hope this will help you understand a bit more how the AJAX works.
PS. You will have to update your controller as well to return the results, in your instance will be
#PostMapping("/exercise")
public createExerciseDomainTYPEHERE createExercise(#RequestBody final ExerciseDTO exerciseDto) {
final Exercise exercise = this.modelMapper.map(exerciseDto, Exercise.class);
//this.exerciseService.createExercise(exercise);
//return "exercise";
return this.exerciseService.createExercise(exercise);
}
You will have to change this line
public createExerciseDomainTYPEHERE createExercise(#RequestBody final ExerciseDTO exerciseDto) {
to your createExercise Domain Type.

Attempting to make a delete button in Thymeleaf / Spring MVC

Attempting to make a button for much longer than one would assume it takes for a newbie.
The Error message I'm getting is:
'java.lang.String' to required type 'java.lang.Long'; nested exception is java.lang.NumberFormatException: For input string: "${id}"
What am I doing wrong? Thanks in advance.
My Controller:
#Controller
public class BuyerController {
private BuyerService buyerService;
#Autowired
public void setBuyerService(BuyerService buyerService){
this.buyerService = buyerService;
}
#RequestMapping("/add-buyer")
public String showBuyerPager(Model model){
List<Buyer> buyers = buyerService.findAllBuyers();
model.addAttribute("buyers", buyers);
model.addAttribute("buyer", new Buyer());
return "add-buyer";
}
#GetMapping("/showBuyerForm")
public String addBuyerForm(Model model){
model.addAttribute("buyer", new Buyer());
model.addAttribute("buyerId", new Buyer().getBuyerId());
return "add-buyer";
}
#PostMapping("/addBuyer")
public String postBuyerForm(#ModelAttribute("buyer") Buyer buyer, Model model){
buyerService.saveBuyer(buyer);
model.addAttribute("buyer", new Buyer());
return "redirect:/";
}
#PostMapping("/deleteBuyer/{id}")
public String deleteBuyer(#PathVariable Long id){
buyerService.deleteBuyer(id);
return "redirect:/";
}
}
View:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Title</title>
<link href="styles.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<header> Welcome to Toner Stock </header>
<h1>Add Buyer</h1>
<div id="mynav" align="center">
<ul>
<li>Home</li>
<li>Add Buyer</li>
<li>Add Manager</li>
<li>Current Stock</li>
<li>Transactions</li>
<li>Order Form</li>
</ul>
</div>
<div id="display-table" align="center">
<form th:action="#{/addBuyer}" th:object="${buyer}" style="width:100%" method="post">
<table>
<td><label>First Name: </label></td>
<td><input type="text" th:field="*{firstName}"/></td>
<td><label>Last Name: </label></td>
<td><input type="text" th:field="*{lastName}"/></td>
<td><label>Enter Address: </label></td>
<td><input type="text" th:field="*{buyerAddress}"/></td>
<td><input type="submit" value="save"/></td>
</table>
</form>
</div>
<div>
<div>
<table id="info-table" align="center" border="1">
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Address</th>
</tr>
<tr th:each="buyer : ${buyers}">
<td th:text="${buyer.firstName}"></td>
<td th:text="${buyer.lastName}"></td>
<td th:text="${buyer.buyerAddress}"></td>
<td>
<form th:action="#{/deleteBuyer/${id}}" th:object="${buyer}" method="post">
<input type="hidden" th:field="${buyer}">Delete</input>
<button type="submit" onClick="return confirm('sure?')"/>
</form>
</td>
</tr>
</table>
</div>
</div>
<div>
<select>
<option th:each="buyer : ${buyers}"
th:text="${buyer.firstName}"
th:value="${buyer.buyerId}"
></option>
</select>
</div>
<div>
<div>
</div>
</div>
</body>
</html>
I'm not a thymeleaf expert but it looks like your form th:action="#{/deleteBuyer/${id}}" should be th:action="#{/deleteBuyer/{id}(id=${buyer.buyerId})}"

Method Not Allowed, status=405 trying to make a delete entity button

Not sure what I'm doing wrong on this one. Attempting to make a button that can delete added entities from database. I'm getting a 405 error but I am not sure if I'm getting this because of something I'm doing in the controller or something badly I wrote in thymeleaf. Thanks for any help.
Controller:
#Controller
public class BuyerController {
private BuyerService buyerService;
#Autowired
public void setBuyerService(BuyerService buyerService){
this.buyerService = buyerService;
}
#RequestMapping("/add-buyer")
public String showBuyerPager(Model model){
List<Buyer> buyers = buyerService.findAllBuyers();
model.addAttribute("buyers", buyers);
model.addAttribute("buyer", new Buyer());
return "add-buyer";
}
#GetMapping("/showBuyerForm")
public String addBuyerForm(Model model){
model.addAttribute("buyer", new Buyer());
model.addAttribute("buyerId", new Buyer().getBuyerId());
return "add-buyer";
}
#PostMapping("/addBuyer")
public String postBuyerForm(#ModelAttribute("buyer") Buyer buyer, Model model){
buyerService.saveBuyer(buyer);
model.addAttribute("buyer", new Buyer());
return "redirect:/";
}
#GetMapping("/deleteBuyer")
public String deleteBuyer(#RequestParam("buyerid") Long id){
buyerService.deleteBuyer(id);
return "redirect:/";
}
}
View:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Title</title>
<link href="styles.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<header> Welcome to Toner Stock </header>
<h1>Add Buyer</h1>
<div id="mynav" align="center">
<ul>
<li>Home</li>
<li>Add Buyer</li>
<li>Add Manager</li>
<li>Current Stock</li>
<li>Transactions</li>
<li>Order Form</li>
</ul>
</div>
<div id="display-table" align="center">
<form th:action="#{/addBuyer}" th:object="${buyer}" style="width:100%" method="post">
<table>
<td><label>First Name: </label></td>
<td><input type="text" th:field="*{firstName}"/></td>
<td><label>Last Name: </label></td>
<td><input type="text" th:field="*{lastName}"/></td>
<td><label>Enter Address: </label></td>
<td><input type="text" th:field="*{buyerAddress}"/></td>
<td><input type="submit" value="save"/></td>
</table>
</form>
</div>
<div>
<div>
<table id="info-table" align="center" border="1">
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Address</th>
</tr>
<tr th:each="buyer : ${buyers}">
<td th:text="${buyer.firstName}"></td>
<td th:text="${buyer.lastName}"></td>
<td th:text="${buyer.buyerAddress}"></td>
<td>
<form th:action="#{/deleteBuyer}" th:object="${buyer}" method="post">
<input type="hidden" name="buyerid" id="buyerid" value="${buyer.buyerId}"/>
<input type="submit" value="Delete" onClick="return confirm('sure?')"/>
</form>
</td>
</tr>
</table>
</div>
</div>
<div>
<select>
<option th:each="buyer : ${buyers}"
th:text="${buyer.firstName}"
th:value="${buyer.buyerId}"
></option>
</select>
</div>
<div>
<div>
</div>
</div>
</body>
</html>
I don't know much about Thymeleaf but you can keep it simpler and change your front-end code from form to basic link :
<c:url var="deleteBuyer" value="/DeleteBuyer">
<c:param name="buyerId" value="${buyer.buyerId}" />
</c:url>
<a class="simpleLink" href="${deleteBuyer}">delete</a>
And handle it in your controller :
` #GetMapping("/DeleteBuyer")
public String deleteAnswer(#RequestParam("buyerId") int theId) {
buyerService.deleteBuyer(theId);
return "redirect:/";
}`
I hope this help you.
Change the
<form th:action="#{/deleteBuyer}" th:object="${buyer}" method="post">
To GET to conform with the Spring request mapping
<form th:action="#{/deleteBuyer}" th:object="${buyer}" method="get">
Here are all available HTTP Methods

Spring MVC second Post method #ModelAttribute is null

I have a form that has two buttons, a submit button and an update button.
Here is the JSP:
<%# page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<!-- Bootstrap core CSS !-->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<!-- Custom scripts/styles for this page !-->
<script type="text/javascript" src="${pageContext.request.contextPath}/static/script/jquery.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/static/script/script.js"></script>
<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/static/css/style.css" />
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Test</title>
</head>
<body>
<!-- General Information Form -->
<form:form id="form" method="POST" action="${pageContext.request.contextPath}/create" modelAttribute="task">
<div id="general">
<table style="width: 224px;">
<tr>
<td colspan="2"><form:select id="systemType" path="systemType" items="${systemTypes}" /></td>
</tr>
<tr>
<td id="buffer"></td>
</tr>
<tr>
<td colspan="2"><form:select id="userName" path="user.fullName" items="${userFullNames}" /></td>
</tr>
<tr>
<td id="buffer"></td>
</tr>
<tr>
<td style="width: 50%;"><label for=line><b>Line: </b></label></td>
<td><form:select path="location.line" items="${lines}" id="line"/></td>
</tr>
<tr>
<td id="buffer"></td>
</tr>
<tr>
<td style="width: 50%;"><label for=position><b>Position: </b></label></td>
<td><form:select path="location.position" items="${positions}" id="position" /></td>
</tr>
<tr>
<td id="buffer"></td>
</tr>
<tr>
<td colspan="2">
<input id="submitButton" type="submit" name="submit" value=Submit />
<input style="display:none;" id="updateButton" type="submit" name="update" value="Update" />
<input id="cancel" style="float: right;" type="Reset" value="Cancel" />
</td>
</tr>
</table>
</div>
</form:form>
</body>
</html>
Here is my controller:
#Controller
#RequestMapping("/")
public class HomeController {
private TaskService taskService;
#Autowired
public void setTaskService(TaskService taskService) {
this.taskService = taskService;
}
#RequestMapping(value = "/", method = RequestMethod.GET)
public String initForm(Model model, HttpServletRequest request) {
Task task = new Task();
model.addAttribute("task", task);
return "home";
}
#RequestMapping(value="/create", params="submit", method = RequestMethod.POST)
public String submitForm(#ModelAttribute("task")Task task,BindingResult result, Model model) {
taskService.create(task);
return "redirect:/";
}
#RequestMapping(value="/create", params="update", method = RequestMethod.POST)
public String updateForm(#ModelAttribute("task")Task task, BindingResult result, Model model) {
System.out.println("Updating: " + task.toString());
taskService.update(task);
return "redirect:/";
}
The idea being that hitting the submit button will make a new item, and the update button will edit an existing one. The two .POST methods have different parameters specified to distinguish them.
The submit button is working as expected. However when the update button is pressed a Task object is delivered to the updateForm controller method - but all of its fields are null.
I am not sure why the form is binding the fields to the Task correctly on the submit method, but seemingly creating a new Task and not binding it at all in the update method.
I am inclined to just combine these methods into a single controller method and use some Java logic to determine whether to submit/update based on the parameter - but am curious as to what I'm missing and why this doesn't work.
Ok, I feel very stupid. This was not a SpringMVC issue at all. The problem was caused by a Jquery method that was disabling a part of the form. This gave the appearance that the form was not binding, but actually it was just binding to null values.

Categories

Resources