Values for th:field attributes in checkbox - spring

I have table with datas from database (insert dynamically). In one column I insert checkbox. Now I want to select one of them and send to next form (I select one product and send properties to another form. In this form should be displayed properties only the select product). But I don't know what kind of value insert in th:field="*{}". I tried many solutions but doesn't work. My html form with all products table:
<form action="/oferta/zamow" th:action="#{/oferta/zamow}"
th:object="${oferta}" method="post">
<table border="1" id="display-data">
<tr>
<td>#</td>
<td>title</td>
<td>author</td>
<td>rok</td>
<td>cena</td>
<td></td>
</tr>
<tr th:each="produkt, pozycja : ${oferta}">
<td th:text="${pozycja.count}"></td>
<td><span th:text="${produkt.tytul}"></span></td>
<td><span th:text="${produkt.autor}"></span></td>
<td><span th:text="${produkt.rok}"></span></td>
<td><span th:text="${produkt.cena}"></span></td>
<td>
<input type="submit" value="zamow"/>
<!-- <a th:href="#{/zamowienie}">zamow</a> -->
</td>
<td>
<label>zamow</label>
<input type="checkbox" th:field="*{produkt}" th:value="${produkt}"/>
</td>
</tr>
</table>
</form>
Form to display select product:
<form action="/zamowienie/zam" th:action="#{/zamowienie/zam}"
th:object="${zamowienie}" method="post">
<table border="1" id="display-data">
<tr align="center">
<td colspan="2">twoje zamowienie</td>
</tr>
<tr>
<td>tytul</td>
<td><span th:text="${produkt.tytul}"></span></td>
</tr>
<tr>
<td>autor</td>
<td><span th:text="${produkt.autor}"></span></td>
</tr>
<tr>
<td>rok</td>
<td><span th:text="${produkt.rok}"></span></td>
</tr>
<tr>
<td>cena</td>
<td><span th:text="${produkt.cena}"></span></td>
</tr>
<tr>
<td>data zlozenia zamowienia</td>
<td><span th:text="${datazam}"></span></td>
</tr>
</table>
</form>
Thanks for help.

I am not sure if this is the answer you seek, but you can find an example at http://www.thymeleaf.org/doc/html/Thymeleaf-Spring3.html#checkbox-fields.
Here is a simple example to illustrate how to use a checkbox in Thymeleaf with Spring MVC.
Controller:
#RequestMapping(value = "/showForm", method=RequestMethod.GET)
public String showForm(Model model) {
List<String> allItems = new ArrayList<String>();
allItems.add("value1");
allItems.add("value2");
allItems.add("value3");
model.addAttribute("allItems", allItems);
Foo foo = new Foo();
List<String> checkedItems = new ArrayList<String>();
// value1 will be checked by default.
checkedItems.add("value1");
foo.setCheckedItems(checkedItems);
model.addAttribute("foo", foo);
...
}
#RequestMapping(value = "/processForm", method=RequestMethod.POST)
public String processForm(#ModelAttribute(value="foo") Foo foo) {
// Get value of checked item.
List<String> checkedItems = foo.getCheckedItems();
...
}
html:
<form action="#" th:action="#{/processForm}" th:object="${foo}" method="post">
<div th:each="item : ${allItems}">
<input type="checkbox" th:field="*{checkedItems}" th:value="${item}" />
<label th:text="${item}">example</label>
</div>
<input type="submit" />
</form>
Foo.java:
public class Foo {
private List<String> checkedItems;
public List<String> getCheckedItems() {
return checkedItems;
}
public void setCheckedItems(List<String> checkedItems) {
this.checkedItems = checkedItems;
}
}
Hope this helps.

Take a look at the thymeleaf spring integration docs.
All th:field are mapped against the command object. Thats why you need the *{} expression.
One thing the template engine is not able to do (yet) is mapping fields inside a loop directly. So you cannot use the *{} approach to reference the produkt variable from the loop.
What you have to do is use the index of the th:each expression and build a property accessor with a pre-evaluated expression for the index.
<input type="checkbox" th:field="*{produkts[__${index}__].checked" />
You do not need the th:value, th:field is taking care of it. (Except if you want to superseed it)

Related

Mvc Core: Validation attributes are generated once for dublicated names

This is a question just like an old one but in the old one, the reason for that is marked as the answer.
My page, there is a form that contains several items. Each item contains a few elements so their name is duplicated.
<form ...>
.....
<table class="details">
<thead>
<tr>
<th>Prop1</th>
<th>Prop2</th>
</tr>
</thead>
<tbody>
#foreach(var item in Model.Items)
{
#await Html.PartialAsync("partial-view-name", detail)
}
</tbody>
</table>
...
</form>
The partial
....
<tr>
<td><input asp-for="Prop1" /></td>
<td><input asp-for="Prop2" /></td>
</tr>
As mentioned here this is the designed behavior, but I wondered if there is any way to override it.
I think your issue is how you are rendering out each object to the screen. If you apply the logic below it should render correctly and also bind back to the list correctly on submit.
#for (int i=0; i< Model.Items.Count; i++)
{
<div class="text-center">
<label asp-for="#Model.Items[i].Prop1"></label>
<input asp-for="#Model.Items[i].Prop1" />
<label asp-for="#Model.Items[i].Prop2"></label>
<input asp-for="#Model.Items[i].Prop2" />
</div>
}
I found a solution to add a prefix to the HTML fields so the name would be different in the iterations.
#{ ViewData.TemplateInfo.HtmlFieldPrefix = Model.ID; }
<tr>
<td><input asp-for="Prop1"/></td>
<td><input asp-for="Prop2"/></td>
</tr>

Dynamic row thymeleaf

I want to create dynamic adding and removing list rows in Thymeleaf and Spring Boot.
I don't know how to use thymeleaf in dynamic rows, but i am trying to do it
So this is my code:
public class Form{
private List<Obj> list = new ArrayList<>();
//...
}
public class Obj{
private String a;
}
Controller:
#GetMapping("/form")
public String form(Model model) {
model.addAttribute("form", new Form());
return "/form";
}
HTML:
[...]
<form class="form-horizontal row-border" action="#" th:action="#{/form}" th:object="${form}" method="post">
<div class="form-group">
<div class="col-md-12">
<div class="row">
<label class="col-md-2 control-label">...</label>
<div class="col-md-10">
<table id="myTable" class=" table order-list">
<thead>
<tr>
<td>String</td>
</tr>
</thead>
<tbody>
<tr th:each="row:${list}">
<td class="col-sm-1">
1
</td>
<td class="col-sm-3">
<input th:field="*{list[__${row.index}__].a}" type="text" name="xyz" class="form-control"/>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="5" style="text-align: left;">
<input type="button" class="btn btn-lg btn-block " id="addrow" value="Add row" />
</td>
</tr>
<tr>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</div>
</form>
[...]
but i don't know how to get send data from form to controller
The controller recieves your data based on the input names. th:field sets your input name in the proper way so the controller will recieve it.
Sadly, if you add a new row in the client, where thymeleaf doesn't exist anymore, you have to set the proper name manually. You can look up for which name to set in your new row inputs with a js function like this (or any other way):
var nextRow = 0;
while($("input[name='list[" + nextRow + "].a']").length){
nextRow ++;
}
nextRow will have the next free row, just use it to build a name in the fashion of the ones thymeleaf generates and set it as your new input's name.

Pass id to the controller

Firstly, I am passing values from database to the table. In the first column I want to create a form that will pass the id to delete function in Controller.
<tr th:each="blg: ${all}" th:object="${blg}" >
<td>
<form th:action="#{/delete}" th:object= "${blg}" method="post">
<input type="text" th:field="${blg.id}"/>
<button type="submit">Delete</button>
</form>
</td>
<td th:text="*{title}"> title </td>
<td th:text="*{content}"> title </td>
<td th:text="*{category}"> title </td>
<td th:text="*{signature}"> title </td>
</tr>
Controller:
#GetMapping("/show")
public String show(Model model){
List<Blog> all = br.findAll();
model.addAttribute("all",all);
return "show";
}
#RequestMapping(value="/delete", method=RequestMethod.POST)
public String deletePost(#RequestParam Long id){
br.delete(id);
return "redirect:/show";
}
The thymeleaf engine doesn't map the object as this error occcurs:
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'blg' available as request attribute.
What is the way to create a correct form in this case?
Update your html code as shown below:
<tr th:each="blg: ${all}" >
<td>
<form th:action="#{|/delete/${blg.id}|}" method="post">
<button type="submit">Delete</button>
</form>
</td>
<td th:text="${blg.title}"> title </td>
<td th:text="${blg.content}"> title </td>
<td th:text="${blg.category}"> title </td>
<td th:text="${blg.signature}"> title </td>
</tr>
Better to use HTTP method DELETE for delete operations.
The reason because th:object tried to look in your request attribute for the attribute blg. But blg is a result of an iteration.

Getting the selected values from a checkbox list to the controller with Spring Boot

I'm using Spring Boot with Thymeleaf as viewer, and I want to delete all selected items from a table. Therefore, I need to pass to the controller a list with the values from the selected checkboxes.
This is my approach for the controller:
#PostMapping("/admin/rates/prices/delete")
public String delete(#ModelAttribute Rate price, ServletWebRequest request){
if(request.getParameterValues("idChecked") != null){
for(String idCheckedStr : request.getParameterValues("idChecked")){
int idrate = Integer.getInteger(idCheckedStr);
rateRepository.deleteRate(idrate);
}
}
return "redirect:/admin/rates/prices";
}
I get a Null Pointer Exception:
java.lang.NullPointerException: null
at com.rentalwebs.controllers.rates.PriceListController.delete(PriceListController.java:42)
I think this method should collet the values::
request.getParameterValues("idChecked")
This is the line at the form, which creates each checkbox with the Thymeleaf annotations:
<input type="checkbox" th:name="idChecked" th:value="${price.idrate}"/>
That's the view code for the form:
<form th:action='#{/admin/rates/prices/delete}'
method="POST"
th:object="${rate}">
<button type="submit" name='delete' value="delete"
class='btn btn-secondary btn-sm'
th:text="#{delete}"
data-toggle="tooltip" data-placement="right"
th:title="#{delete.selected}">
</button>
<p></p>
<table class='table table-sm responsive'>
<thead class='thead-default'>
<tr>
<th><input type="checkbox" id="checkAll"/></th>
<th th:text='#{from}'></th>
<th th:text='#{to}'></th>
<th th:text='#{price}'></th>
</tr>
</thead>
<tbody>
<tr th:each="price : ${prices}">
<td>
<input type="checkbox" th:name="idChecked" th:value="${price.idrate}"/>
</td>
<td th:text="${#temporals.format(price.datefrom, 'dd/MM/yyyy')}"></td>
<td th:text="${#temporals.format(price.dateto, 'dd/MM/yyyy')}"></td>
<td th:text="${price.price} + ' €'"></td>
</tr>
</tbody>
</table>
</form>
Thank you in advance for your help :-)
This is the code with the solution, taken from the comments:
#PostMapping("/admin/rates/prices")
public String delete(#RequestParam("idChecked") List<String> idrates){
if(idrates != null){
for(String idrateStr : idrates){
int idrate = Integer.parseInt(idrateStr);
rateRepository.deleteRate(idrate);
}
}
return "redirect:/admin/rates/prices";
}

share 'form fragment' between createForm.html, updateForm.html on thymeleaf

I use thymeleaf on spring.
I don't want to produce duplicated html page createForm.html and updateForm.html.
Maybe It requires copy & paste.
My code is below.
<form class="form-horizontal" role="form" th:action="${!template.new#{/templates}" method="post"
th:object="${template}">
...
</form>
When template is before saving(=create), action is '/templates'.
When tempalte is after saving(=update), action is '/templates/UUID/edit'.
=> It is rails convention.
You can also add this address to the ModelMap:
modelMap.add("address", "/templates")
th:action="#{${address}}"
HTML
<div class="form-group">
<label for="objectName">Name</label>
<input type="text" class="form-control" th:value="${object.name}" name="name"
id="objectName" placeholder="Name"/>
</div>
bottom HTML
<div class="table-responsive">
<table class="table table-bordered table-hover table-striped">
<thead>
<tr>
<th>Name 1</th>
<th>Name 2</th>
<th>Name 3</th>
</tr>
</thead>
<tbody>
<tr data-th-each="eachObject : ${obj}">
<td><a data-th-text="${eachObject.name}" th:href="#PATH/edit?Name=}+${eachObject.name}">...</a></td>
<td data-th-text="${eachObject.name2}">...</td>
<td data-th-text="${eachObject.name3}">...</td>
<td><a th:href="#{/PATH/delete?objname=}+${eachObject.name}">delete</a></td>
</tr>
</tbody>
</table>
</div>
Controller
#RequestMapping(value = "/create",method = RequestMethod.GET)
public String createMethod(Model model) {
Object obj = new Object();
model.addAttribute("Object", obj);
return "htmlpage";
}
controller
#RequestMapping(value = "/form/save", method = RequestMethod.POST)
public String campaignPost(#ModelAttribute("object") Object obj, Principle prin, Model model){
service.save(obj);
}

Resources