Is it possible to use Spring model in Javascript functions inside Thymeleaf template? - spring

I've the following domain:
#Document(collection = "backupareas")
public class BackupArea {
#Id
private String id;
private String area;
private List<Tape> tapes;
In my template I would that when I change area a js function fill the tape select with related area tapes.
<div class="form-group col-md-3">
<label for="backup"><i>*</i> Backup</label>
<select id="backup" class="form-control" name="backup" required onchange="loadTapes();">
<option value="" selected="selected">--- Select Area ---</option>
<option th:each="area: ${areas}" th:value="${area.getArea()}" th:text="${area.getArea()}"></option>
</select>
</div>
<div class="form-group col-md-3">
<label for="tape"><i>*</i> Tape</label>
<select id="tape" class="form-control" name="tape" required >
</select>
I start with this js function, but I don't know how to use (or if it is possible) model variables.
function loadTapes() {
var area = $("#backup").val();
console.log($("#backup").index(area));
if($("#backup").index(area) == 1) {
$("#tape").empty();
return false;
}
$("#tape").empty();
var select = $('#tape');
select.append($("<option />").val("").text("--- Select one ---"));
// Here should use model variable to loop over tapes related to the selected area
select.append($("<option/>").val(TAPE).text(TAPE));
}

I solved. I created a fragment as:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
<th:block th:fragment="tapes">
<th:block th:if="${tapes != null}">
<option th:each="tape: ${tapes}" th:value="${tape}" th:text="${tape}"></option>
</th:block>
</th:block>
</body>
</html>
In the main template I call an ajax method:
function loadTapes() {
$("#tape").empty();
$.post("/area/loadTapes", {area: area}, function (data) {
$('#tape').append(data);
});
}
The loadTapes method is:
PostMapping("/area/loadTapes")
public String loadTape(#RequestParam("area") String area, Model model) {
BackupArea backupArea = backupAreaService.findByArea(area);
List<Integer> tapes = new ArrayList<>();
for(Tape tape: backupArea.getTapes()) {
tapes.add(tape.getTape());
}
model.addAttribute("list", tapes);
return "/backup/tapes :: list";
}

Related

Retrieving Information from Userinput SpringMVC dropdown box

Hi I'm having some trouble retrieving information from the user using a spring controller.
the controller looks like this:
#Slf4j
#Controller("indexController")
public class IndexController {
List<String> userInput = new ArrayList<>(Arrays.asList(new String[]{"Apple", "Blackberry", "Strawberry"}));
public List<String> getUserInput() {
return userInput;
}
#RequestMapping(value = "/home", method = RequestMethod.GET)
public String home(
Model model
){
log.info("home path was hit");
model.addAttribute("options", getUserInput());
model.addAttribute("option", new Object());
return "index";
}
#RequestMapping(value = "createOrder", method = RequestMethod.POST)
public String placeUserOrder(
Model model,
#ModelAttribute("option")String usersInput
){
log.info("createOrder path was hit");
log.info(usersInput);
return "redirect:/home";
}
the index.thml within re main/resource/templates folder looks like this:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>home page</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<h2>your orders are:</h2>
<form method="post" action="/createOrder" th:object="${order}">
<th:text alignment-baseline="text-before-edge" aria-atomic="true" > select a copybook</th:text>
<select class="from-control" id="dropDownList">
<option value="0">select copybook</option>
<option th:each="option : ${options}" th:value="${option}" th:text="${option}" >
<input type="hidden" name="${_csrf.usersChoiceFromThymeleaf}" value="${_csrf.token}" />
</option>
<input type="submit" name="createOrder" value="place">
</select>
</p>
</p>
</form>
<th:block th:each="order : ${orders}">
<tr>
<td th:text="${order.value}"></td>
</tr>
</th:block>
</body>
</html>
every time after i set a breakpoint within the post function the option value is empty.
what am i doing wrong?
shouldnt i expect a string from selected dropdown menu?
i tried to fetch an int and it remains empty as well
the model contains also only 2 key value pairs "option"->""
and org.springframework.validation.BindingResult.option -> {BeanPropertyBindingResult#7472} "org.springframework.validation.BeanPropertyBindingResult: 0 errors"

Spring Boot Thymeleaf Method POST SELECT null

Guys.
Tell me please how to get values from select in the Controller?
This returns null.
request.getParameter("firstUserYears");
request.getParameter("secondUserYears");
I want to get value of "birthDay" field.
my thymeleaf html form:
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form method="post" action="/calculate_years">
<select name="firstUserYears" th:field="*{users}"/>
<option th:each="user : ${users}" th:value="firstUserYears" th:text="${user.firstName}">
</option>
</select>
<select name="secondUserYears" th:field="*{users}"/>
<option th:each="user : ${users}" th:value="${user.firstName}" th:text="${user.firstName}">
</option>
</select>
<button type="submit">Submit</button>
</form>
</body>
</html>
Controller:
#GetMapping("/user-difference")
public String calculateDifferenceForm(Model model) {
model.addAttribute("users", service.findAll());
return "user-difference";
}
#PostMapping("/calculate_years")
public String calculateDifferenceForm(HttpServletRequest request, #ModelAttribute User user,
BindingResult bindingResult){
String firstUsersYearsOld = request.getParameter("firstUserYears");
String secondUsersYearsOld = request.getParameter("secondUserYears");
String name = request.getParameter("name");
BindingResult results = bindingResult;
System.out.println(results);
System.out.println(user);
System.out.println(name);
System.out.println(firstUsersYearsOld);
System.out.println(secondUsersYearsOld);
return "redirect:/user-difference";
}
You should start with defining a form data object. For example:
public class AgeDifferenceFormData {
private long user1Id;
private long user2Id;
// getters and setters here
}
Create an empty such object in your #GetMapping:
#GetMapping("/user-difference")
public String calculateDifferenceForm(Model model) {
model.addAttribute("formData", new AgeDifferenceFormData());
model.addAttribute("users", service.findAll());
return "user-difference";
}
Now update your HTML form to use the form data object:
<form method="post" action="/calculate_years" th:object="${formData}">
<select th:field="*{user1Id}"/>
<option th:each="user : ${users}" th:value="${user.id}" th:text="${user.firstName}">
</option>
</select>
<select th:field="*{user2Id}"/>
<option th:each="user : ${users}" th:value="${user.id}" th:text="${user.firstName}">
</option>
</select>
<button type="submit">Submit</button>
</form>
Note how you need to:
Set a selected object for Thymeleaf via th:object="${formData}"
Set the dedicated field for each select via th:field="*{user1Id}" and th:field="*{user2Id}"
Use the unique id of the user for the th:value.
Now in your #PostMapping method do this:
#PostMapping("/calculate_years")
public String calculateDifferenceForm(#ModelAttribute("formData") AgeDifferenceFormData formData,
BindingResult bindingResult){
User user1 = service.getUser(formData.getUser1Id());
User user2 = service.getUser(formData.getUser2Id());
// calculate age difference here
return "redirect:/user-difference";
}
See also Using HTML select options with Thymeleaf for more info.

How pass extra param from html to controller

Spring Boot 2.5, Thymeleaf
I need when click submit to pass object Product and additional extra param (quantity)
html template:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title th:text="${appName}">Category template title</title>
<link th:href="#{/public/style.css}" rel="stylesheet"/>
<meta charset="UTF-8"/>
</head>
<body>
<div class="container">
<h3 th:text="*{title}"/>
<form method="post" action="#" th:object="${product}" th:action="#{/product}">
<input type="hidden" id="id" th:field="*{id}"/>
<input type="text" placeholder="Name" id="name" th:field="*{name}" th:disabled="${isView}"/>
<input type="hidden" id="created" th:field="*{created}"/>
<textarea placeholder="Description" rows="5" id="description"
th:field="*{description}" th:disabled="${isView}"></textarea>
<input type="number" placeholder="Price" id="price" th:field="*{price}" th:disabled="${isView}"/>
<input type="text" placeholder="Currency" id="currency" th:field="*{currency}" th:disabled="${isView}"/>
<input type="text" placeholder="Images URL(separate by comma)" id="images" th:field="*{images}" th:disabled="${isView}"/>
<input th:type="${isView} ? hidden : submit" value="Submit"/>
</form>
</div>
</body>
</html>
and here my controller:
#RequestMapping("cart/add")
public String addProduct(Model model) {
logger.info("addProduct");
model.addAttribute("isAdd", true);
model.addAttribute("product", new Product());
model.addAttribute("title", "Add Product");
model.addAttribute("viewMode", ViewMode.ADD);
return "product";
}
#PostMapping(value = "/product")
public String submitProduct(Product product, Model model) {
logger.info("submitProduct = " + product);
if (product.getId() == 0) { // add category
product.setCreated(new Date());
} else { // update category
product.setUpdated(new Date());
}
return "redirect:/cart";
}
So when click button Submit call submitProduct with fill object Product. But I need to pass extra param (as second param in method submitProduct) - quantity.
How I can pass this extra int param from html to controller?
One option is to access the value directly from the request parameters.
Assuming the quantity value is available in the form as an input field, with a name of quantity (looks like it is not there at the moment), then you can alter your controller to use this:
import org.springframework.web.bind.annotation.RequestParam;
And then change the relevant method signature to something like this:
public String submitProduct(Product product, Model model,
#RequestParam(name = "quantity") String quantity) {...}
(Field validation of some kind would also be needed, I assume.)

Pass a list of user defined object from input field using spring form handling

I have an Employee class that looks like this.
public class Employee {
private String Name;
private List<Address> address;
*****Getters and Setters****
}
And my Address class looks like this
public class Address {
private int addressid;
private Employee employee;
#NotNull(message="Field Cannot be Empty")
private String description;
*****Getters and Setters****
}
I want to bind List of addresses (Employee can have more than one address - 1:M) to the employee class with the data that is parsed through the form. Which looks like this.
I have 3 input address fields, one of the sample input fields look like this...
<div class="form-group">
<div class="row">
<label class="col-sm-3" for="exampleInputEmail1">Address
1</label>
<div class="col-sm-7">
<form:input class="form-control" placeholder="" path="" />
<form:errors path="" cssClass="error" />
</div>
</div>
</div>
Note that I have cut down many unnecessary form fields to demonstrate the problem more clearly. Please help me bind the list of input fields with the relevant class. Any advice for this design is also welcome.
You can use Thymeleaf for this as below.
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>form|data</title>
</head>
<body>
<div class="starter-template">
<form th:action="#{employeeData}" method="post" th:object="${employee}">
<input th:field="*{name}" type="text" th:name="name" name="name" placeholder="name" class="input u-one-third js-get-form-data"/>
<th:block th:each="add,addStat:*{address}">
<input th:field="*{address[__${addStat.index}__].description}" type="text" th:name="add.description" name="description" placeholder="description" class="input u-one-third js-get-form-data"/>
</th:block>
<input type="submit" value="SEND"/>
</form>
</div>
</body>
</html>
Controller.
#RequestMapping(value = "/formData", method = RequestMethod.GET)
public String formData(Map<String, Object> model) {
Employee employee = new Employee();
Address address = new Address();
address.setDescription("TEST");
address.setEmployee(employee);
employee.getAddress().add(address);
model.put("employee",employee);
return "formData";
}
#RequestMapping(value = "/employeeData", method = RequestMethod.POST)
public void employeeData(#Valid Employee employeeData, BindingResult errors) {
System.out.println(employeeData.getName());
}
Please find the working commit here.

Rendering html entities in webforms DropDownList control

I am trying to use html entities in in a DropDownList control. The reason I am using entities is because I want to display units with superscripts such as m²/s or kg/m³. sup is not an option because it doesn't work inside a select option tag. I have created a small example that illustrates my problem. Here is my aspx page:
<!DOCTYPE html>
<html lang="en">
<head runat="server">
<meta charset="utf-8" />
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<select>
<option value="1">M³/min</option>
<option value="2">M³/s</option>
</select>
<asp:DropDownList ID="drp" runat="server"></asp:DropDownList>
</div>
</form>
</body>
</html>
and here is my code behind:
public partial class MyPage: System.Web.UI.Page
{
private class idAndUnit
{
public int Id { get; set; }
public string Unit { get; set; }
}
protected void Page_Load(object sender, EventArgs e)
{
var units = new List<idAndUnit>()
{
new idAndUnit
{
Id = 1,
Unit = "M³/min"
},
new idAndUnit
{
Id = 2,
Unit = "M³/min"
}
};
drp.DataSource = units;
drp.DataTextField = "Unit";
drp.DataValueField = "Id";
drp.DataBind();
}
}
If you run the page and look at the source html it generates you see the following:
<select>
<option value="1">M³/min</option>
<option value="2">M³/s</option>
</select>
<select name="drp" id="drp">
<option value="1">M&#179;/min</option>
<option value="2">M&#179;/min</option>
As you can see the DropDownList version has changed M³/min into M³/min.I'm not sure why this change happens presumably either to be helpful in some way or perhaps a security reason for preventing xss or something like that. Is it possible to prevent this behaviour here so I can get the output I'm after?
Just figured it out
using HttpUtility.HtmlDecode("M³/min") fixes it.

Resources