Can't find field (List of custom POJOs) in Thymeleaf? - spring

I have the following code below. Thymeleaf is unable to resolve "orderDetails" despite the field being existent/not null when i debug through the internals of Thymeleaf.
Exception= Field or property 'orderDetails' cannot be found on object of type
<div th:each="order : ${orders}">
<table>
<tr>
<th>CUSTOMER</th>
<th>PRICE</th>
<th>TIME ORDER PLACED</th>
<th>ITEMS</th>
</tr>
<tr>
<td th:text="${order.customerAccount.email}">email</td>
<td th:text="${order.baseCost}">2.50</td>
<td th:text="${order.tip}">2.00</td>
<td th:text="${order.orderDetails}">2.00</td>
<!-- <td th:text="${#lists.size(order.orderDetails)}">1</td> -->
</tr>
</table>
<table>
<tr>
<th>DRINK NAME</th>
<th>AMOUNT</th>
<th>QUANTITY</th>
<th>COST</th>
</tr>
<tr th:each="orderDetail : ${order.orderDetails}">
<td th:text="${orderDetail.barStock.drink.name}">Test Drink Name</td>
<td th:text="${orderDetail.barStock.amount}">10oz</td>
<td th:text="${orderDetail.quantity}">2</td>
<td th:text="${orderDetail.barStock.cost * orderDetail.quantity}">2.00</td>
</tr>
</table>
Here is the field in question of the "order" field/class.
#OneToMany(fetch = FetchType.EAGER, mappedBy = "barOrder")
#JsonProperty
private Set<OrderDetail> orderDetails;

A public getter method for orderDetails field is needed to allow Thymeleaf to access it.
public Set<OrderDetail> getOrderDetails() {
return orderDetails;
}

Related

format nested object to table on thymeleaf

i build crm system,
i had object hes name users he hold also the data from details table (one to many realation)
lets says i had nested object name user and he had more than 1 object of details
i want to get this in the end in thymeleaf table
name | entry date
david | 5/6/22
david | 1/7/22
but i got
name | entry date
david | 5/6/22 , 1/7/22
this is table code on thymeleaf:
<table class="table w-75 table-striped table-dark table-hover">
<thead>
<tr>
<th scope="col" class="text-center">First name</th>
<th scope="col" class="text-center">Entry Date</th>
</tr>
</thead>
<tbody>
<tr th:each="users : ${ParkingUsers}">
<td class="text-center" th:text="${users.firstName}" />
<td class="text-center" th:each="date, i: ${users.parkingDetails}"
th:text="${(i.index > 0 ? '' : '') + date.entryDate}" />
</tr>
</tbody>
</table>
how can i fix that?
thanks
This is a good candidate for using the Thymeleaf th:block tag.
You can place the outer loop (for users) in this tag, and then place the inner loop (for parking details) in the <tr> tag.
Example:
Assume we have two classes:
public class User {
private String firstName;
private List<ParkingDetail> parkingDetails;
// getters and setters
}
And:
public class ParkingDetail {
private LocalDate entryDate;
// getters and setters
}
And assume we have a list of users: List<User>.
We can use the following in our Thymeleaf template:
<table class="table w-75 table-striped table-dark table-hover">
<thead>
<tr>
<th>First name</th>
<th>Entry Date</th>
</tr>
</thead>
<tbody>
<th:block th:each="user : ${users}">
<tr th:each="parkingDetail : ${user.parkingDetails}">
<td th:text="${user.firstName}"></td>
<td th:text="${parkingDetail.entryDate}"></td>
</tr>
</th:block>
</tbody>
</table>
This will generate the following HTML:
<table>
<thead>
<tr>
<th>First name</th>
<th>Entry Date</th>
</tr>
</thead>
<tbody>
<tr>
<td>david</td>
<td>2022-06-05</td>
</tr>
<tr>
<td>david</td>
<td>2022-07-01</td>
</tr>
</tbody>
</table>
The th:block tag allowed Thymeleaf to iterate over the list of users, but it did not cause any HTML to be generated. The Thymeleaf ${user} variable created in the th:block tag can be referenced in all the child tags inside the th:block.
There are various other examples of how th:block can be used, in other questions on this site - so if this does not meet your needs, you can research those other questions.

spring boot and thymeleaf - displaying All Elements

Can you help me about showing all the elements in "book-data".html file?
My controller class is
#Autowired BooksService booksService
#GetMapping("/books")
private List<Books> getAllBooks() throws IOException, InterruptedException {
return booksService.getAllBooks();
}
and my service class is
#Autowired BooksRepository booksRepository;
public List<Books> getAllBooks() throws IOException, InterruptedException {
return (List<Books>) booksRepository.findAll();
}
my book repository interface is
public interface BooksRepository extends CrudRepository<Books, Integer>
{
}
and my "book-data".html file is
<table class="table">
<thead class="thead-dark">
<tr>
<th scope="col">Book ID</th>
<th scope="col">Book Name</th>
<th scope="col">Book Author</th>
<th scope="col">Book Price</th>
</tr>
</thead>
<tbody>
<tr>
<td th:text="${book.bookid}"></td>
<td th:text="${book.bookname}"></td>
<td th:text="${book.author}"></td>
<td th:text="${book.price}"></td>
</tr>
</tbody>
In HTML page, it doesn't show any book data. For service class, I saw another solution like below, but it didn't solve the problem.
#RequestMapping("/books")
private String listBooks(Model model){
model.addAtrribute("books", booksService.getAllBooks());
return "books";
}
in html:
<tbody>
<tr th:each="book : ${books}">
<td th:text="${book.bookid}"></td>
<td th:text="${book.bookname}"></td>
<td th:text="${book.author}"></td>
<td th:text="${book.price}"></td>
</tr>
</tbody>
I think something like this is maybe a solution :
in your controller with adding #Controller in class statement :
#Autowired
BooksService booksService
#GetMapping("/books")
private String listBooks(Model model){
model.addAtrribute("books", booksService.getAllBooks());
return "views/book-data";
}
your service with adding #Service in class statement :
#Autowired
BooksRepository bookRepository
public List<Books> getAllBooks(){
return this.booksRepository.findAll();
}
your repository with adding #Repository in class statement :
maybe you could had #Query
#Repository
public interface BooksRepository extends CrudRepository<Books, Long>
{
public List<Books> findAll();
}
And your html :
<table class="table">
<thead class="thead-dark">
<tr>
<th scope="col">Book ID</th>
<th scope="col">Book Name</th>
<th scope="col">Book Author</th>
<th scope="col">Book Price</th>
</tr>
</thead>
<tbody>
<tr th:each="book : ${books}">
<td th:text="${book.bookid}"></td>
<td th:text="${book.bookname}"></td>
<td th:text="${book.author}"></td>
<td th:text="${book.price}"></td>
</tr>
</tbody>
</table>
First, I created another html file that shows "all books". This file is named allBooks.html. Then, the service method below solved the problem, for your information.
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<html xmlns:th="https://thymeleaf.org">
<style>
table, th, td {
border: 1px solid black;
text-align: center;
}
</style>
<table class="table">
<thead class="thead-dark">
<tr>
<th scope="col">Book ID</th>
<th scope="col">Book Name</th>
<th scope="col">Book Author</th>
<th scope="col">Book Price</th>
</tr>
</thead>
<tbody>
<tr th:each="book : ${books}">
<td th:text="${book.bookid}"></td>
<td th:text="${book.bookname}"></td>
<td th:text="${book.author}"></td>
<td th:text="${book.price}"></td>
</tr>
</tbody>
#GetMapping("/books")
private ModelAndView getAllBooks() throws IOException, InterruptedException {
ModelAndView mav = new ModelAndView();
mav.setViewName("allBooks");
mav.addObject("books", booksService.getAllBooks());
return mav;
}

How can I create dynamic table in Thymeleaf..?

I am new to Thymeleaf and trying to create a dynamic table on Themeleaf template.
How can I do it..??
I have been googling by I didn't got any proper answer. The issue is I cannot iterate List< Map< String,Object >>. I can have any number of columns and columns name could be any thing.
<tr class="headings">
<th class="column-title">ID</th>
<th class="column-title">Name</th>
<th class="column-title">Salary</th>
<th class="column-title">Status</th>
</tr>
</thead>
<tbody>
<tr class="even pointer" th:each="row:${rows}" id = "tablerow">
<td class=" " th:text="${row.getId()}">Id</td>
<td class=" " th:text="${row.getName()}">Name</td>
<td class=" " th:utext="${row.getSalary()}">Salary</td>
<td class=" " th:text="${row.getStatus()}">Active</td>
</tr>
</tbody>
I need to set values dynamically since if query of result will keep changing . right now column name are hard coded and value are also getting by row.getId what if there is no Id, it could be anything in rows what shall I use than..? example row.<>.
rows is obtained as List< Map< String, Object>>.
Thanks in advance.
You can iterative over a Map just as easily as you can a List. The simplest form of this would be:
<tbody>
<tr class="even pointer" th:each="row: ${rows}" id="tablerow">
<td th:each="field: ${row}" th:text="${field.value}" />
</tr>
</tbody>
However, since Maps don't have a specific ordering (unless you're using something like a TreeMap), the way I would do it would be something like this (complete example should match your example table):
Controller
List<String> headers = Arrays.asList("ID", "Name", "Salary", "Status");
List<Map<String, Object>> rows = new ArrayList<>();
rows.add(Map.of("ID", "1", "Name", "Jim", "Salary", "50000", "Status", "active"));
rows.add(Map.of("ID", "2", "Name", "Sally", "Salary", "50000", "Status", "inactive"));
Template
<table>
<thead>
<tr class="headings">
<th th:each="header: ${headers}" class="column-title" th:text="${header}" />
</tr>
</thead>
<tbody>
<tr class="even pointer" th:each="row: ${rows}" id="tablerow">
<td th:each="header: ${headers}" th:text="${row.get(header)}" />
</tr>
</tbody>
</table>
Which will produce:
<table>
<thead>
<tr class="headings">
<th class="column-title" >ID</th>
<th class="column-title" >Name</th>
<th class="column-title" >Salary</th>
<th class="column-title" >Status</th>
</tr>
</thead>
<tbody>
<tr class="even pointer" id="tablerow">
<td >1</td>
<td >Jim</td>
<td >50000</td>
<td >active</td>
</tr>
<tr class="even pointer" id="tablerow">
<td >2</td>
<td >Sally</td>
<td >50000</td>
<td >inactive</td>
</tr>
</tbody>
</table>

Why <td th:each="i : ${#numbers.sequence(0, table_width)}" th:text="${rows[${i}]}"></td> not working

I am trying to Iterate through a list which contains a list of objects, i.e. List I am wondered why this is not working, tried with simply "i", but no luck.
List<Object[]> lists; // logic
model.addObject("lists", lists);
model.addObject("table_width", lists.get(0).length);
Thymeleaf Code Snippet
<table class="table table-responsive table-stripped table-collapsed table-bordered">
<tr th:each="rows,rowStat : ${lists}">
<td th:text="${rowStat.count}"></td>
<td th:each="i : ${#numbers.sequence(0, table_width)}" th:text="${rows[${i}]}"></td>
</tr>
</table>
I have found a way,
<td th:each="i : ${#numbers.sequence(0, table_width-1)}" th:text="${rows[__${i}__]}"></td>
This does the tricks
You can simply iterator over both lists. No need to use the #numbers helper.
<table class="table table-responsive table-stripped table-collapsed table-bordered">
<tr th:each="rows, rowStat : ${lists}">
<td th:text="${rowStat.count}"></td>
<td th:each="value: ${rows}" th:text="${value}"></td>
</tr>
</table>
If you are iterating a collection(list) of objects, try below example:
HTML:
<div th:if="${not #lists.isEmpty(counts)}">
<h2>Counts List</h2>
<table class="table table-striped">
<tr>
<th>Id</th>
<th>Name</th>
</tr>
<tr th:each="count : ${counts}">
<td th:text="${count.id}"></td>
<td th:text="${count.name}"></td>
</tr>
</table>
</div>
Java:
public List<Count> listAll() {
List<Count> counts = new ArrayList<>();
countRepository.findAll().forEach(counts::add);
return counts;
}
Read more info in Thymeleaf Documentation - Iteration Basics section.

Why Xpath 3.0 works, but Xquery 3.0 doesn't work with the same expression

I launched Xpath in Oxygen. In Xpath 3.0 found what i need but in Xquery 3.0 doesn't find.
This is my Xpath expression
//table[tbody/tr/th/p[contains(text(), 'All Water System Contacts')]]/tbody/tr[3]/td[1]
This is my xml code
I put part code.
<table border="1" cellpadding="1" cellspacing="1" summary="." width="640">
<tbody>
<tr>
<th colspan="3">
<p>All Water System Contacts </p></th>
</tr>
<tr>
<th>Type</th>
<th>Contact</th>
<th>Communication</th>
</tr>
<tr>
<td align="center">AC - Administrative Contact - GENERAL MANAGER </td>
<td align="center">GRANT, JOHN, W <br/> PO BOX 869<br/> BIG SPRING, TX 79721-0869 </td>
<td align="center">
<table border="1" cellpadding="0" cellspacing="0" style="border-collapse: collapse"
width="100%">
<tbody>
<tr>
<th><b>Electronic Type</b></th>
<th><b>Value</b></th>
</tr>
</tbody>
</table>
<table border="1" cellpadding="0" cellspacing="0" style="border-collapse: collapse"
width="100%">
<tbody>
<tr>
<th><b>Phone Type</b></th>
<th><b>Value</b></th>
</tr>
<tr>
<td align="center">BUS - Business</td>
<td align="center">432-267-6341 </td>
</tr>
<tr>
<td align="center">FAX - Facsimile</td>
<td align="center">432-267-3121 </td>
</tr>
<tr>
<td align="center">BUS - Business</td>
<td align="center">432-267-6070 </td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td align="center">OW - Owner </td>
<td align="center">COLORADO RIVER MUNICIPAL WATER DISTRICT <br/> PO BOX 869<br/> BIG
SPRING, TX 79721-0869 </td>
<td align="center"> </td>
</tr>
</tbody>
</table>
I tried different functions.
I don't know why it doesn't work and what difference
Please help me.
I suspect your real, complete input has an XHTML default namespace declaration xmlns="http://www.w3.org/1999/xhtml" and in oXygen for XPath you have the setting enabled to "use the default namespace of the root element" so your path works with XPath out of the box while for XQuery you need to make sure you explicitly set
declare default element namespace 'http://www.w3.org/1999/xhtml';
in the prolog of your XQuery file or code sample.

Resources