Print post number in reverse order from thymeleaf - spring-boot

<tbody>
<tr th:each="bean , beanStat : ${list}">
<td class="text-center" th:text="${beanStat.size-beanStat.count+1}+(${paging.cri.page}-1)*${cri.perPageNum}" >1</td>
<!-- paging.totalcount -->
<!-- <tr th:each="bean , beanStat : ${list}">
<td class="text-center" th:text="${beanStat.size-beanStat.count+1}+(${paging.cri.page}-1)*${cri.perPageNum}" >1</td>
First of all, I'm sorry for not speaking English well.
I want to number the articles, but I want to number them in reverse order.
I think you can do it like below in jsp
In thymeleaf, I wonder how to do this in reverse order (is there an index?)
Total number of records - ( (Current page number - 1) * I think it is the number of records displayed per page.
${(totalCount - status.index) - ( (currentPage - 1) * displayNum ) }
I implemented it like this, but I wonder if there is such a part as status.index in the thymeleaf.
enter image description here

There is an equivalent to your JSP approach in Thymeleaf - a set of iteration tracking attributes you can use when processing a list.
Assuming you have a Java list like this:
List<String> list = new ArrayList<>();
list.add("One");
list.add("Two");
list.add("Three");
Then you can use the following Thymeleaf:
<table>
<thead>
<tr>
<th>Number</th>
<th>Item</th>
</tr>
</thead>
<tbody>
<tr th:each="item, iterStat : ${list}">
<td th:text="${iterStat.size - iterStat.count +1}"></td>
<td th:text="${item}"></td>
</tr>
</tbody>
</table>
This generates:
<table>
<thead>
<tr>
<th>Number</th>
<th>Item</th>
</tr>
</thead>
<tbody>
<tr>
<td>3</td>
<td>One</td>
</tr>
<tr>
<td>2</td>
<td>Two</td>
</tr>
<tr>
<td>1</td>
<td>Three</td>
</tr>
</tbody>
</table>
Update
If you want to add paging into the calculation, then your Java code needs to know:
current page number
maximum number of rows per page (there may be fewer in the final page)
total number of records (all pages)
Let's assume I pass those 3 values from Java to my Thymeleaf model with some new data:
List<String> list = new ArrayList<>();
list.add("Alfa");
list.add("Bravo");
list.add("Charlie");
list.add("Delta");
list.add("Echo");
int currentPage = 1;
int rowsPerPage = 5;
int totalRecords = 9;
Now, the Thymeleaf changes to this:
<table>
<thead>
<tr>
<th>Number</th>
<th>Item</th>
</tr>
</thead>
<tbody>
<tr th:each="item, iterStat : ${list}">
<td th:text="${totalRecords - (currentPage * rowsPerPage)
+ rowsPerPage - iterStat.count +1}"></td>
<td th:text="${item}"></td>
</tr>
</tbody>
</table>
For page 1 this generates:
<tbody>
<tr>
<td>9</td>
<td>Alfa</td>
</tr>
<tr>
<td>8</td>
<td>Bravo</td>
</tr>
<tr>
<td>7</td>
<td>Charlie</td>
</tr>
<tr>
<td>6</td>
<td>Delta</td>
</tr>
<tr>
<td>5</td>
<td>Echo</td>
</tr>
</tbody>
For page 2 (the final 4 items), we have:
List<String> list = new ArrayList<>();
list.add("Foxtrot");
list.add("Golf");
list.add("Hotel");
list.add("India");
int currentPage = 2;
int rowsPerPage = 5;
int totalRecords = 9;
Note: Only the current page number has changed. The rows per page and the total records: those values remain the same across all pages.
And the same Thymeleaf template generates this:
<tbody>
<tr>
<td>4</td>
<td>Foxtrot</td>
</tr>
<tr>
<td>3</td>
<td>Golf</td>
</tr>
<tr>
<td>2</td>
<td>Hotel</td>
</tr>
<tr>
<td>1</td>
<td>India</td>
</tr>
</tbody>

Related

3nd parameter does not working, #sortablelink of Kyslik / column-sortable

If the URL has a parameter of the same name, the 3nd parameter does not work.
Current URL is
http://localhost:8000/backend/parts?_tab=1&search_param%5Btab%5D=2&sort=type&direction=asc
My page have two tables, two sort.
<table>
<thead>
<th rowspan="2" class="w100">Status1#sortablelink('status', ' ▲▼', ['_tab'=>1, 'search_param'=>$search_params])</th>
...
</thead>
<tbody>
...
</tbody>
</table>
<table>
<thead>
<th rowspan="2" class="w100">Status2#sortablelink('status', ' ▲▼', ['_tab'=>2, 'search_param'=>$search_params])</th>
...
</thead>
<tbody>
...
</tbody>
</table>
Second table's sort link was too "_tab=1"
http://localhost:8000/backend/parts?_tab=1&search_param%5Btab%5D=2&sort=type&direction=asc
not "_tab=2"
http://localhost:8000/backend/parts?_tab=2&search_param%5Btab%5D=2&sort=type&direction=asc
How to set sort parameter and to change url's parameter in this case?
I expected what url would be
http://localhost:8000/backend/parts?_tab=2&search_param%5Btab%5D=2&sort=type&direction=asc

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.

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>

Select input field according to TH and TR

I have a next table with TH:
<table cellspacing="1" border="1" id="FinancialsGrid">
<thead>
<tr>
<th>Product</th>
<th>Slice</th>
<th>Units</th>
<th>Accrual Rate</th>
<th>Trend Factor</th>
<th>Base Units</th>
</tr>
</thead>
<tbody>
<tr>
<td rowspan="3">Lorem Ipsum</td>
<td>Previous</td>
<td>6,866</td>
<td>0.00 %</td>
<td>0.00 %</td>
<td>6,866</td>
</tr>
<tr>
<td>Current</td>
<td>6,866</td>
<td>0.00 %</td>
<td>0.00 %</td>
<td>6,866</td>
</tr>
<tr>
<td>Proposed</td>
<td>6,866</td>
<td><input type="text" style="width:60px;" value="0.00 %"></td>
<td style="width:60px;"><input type="text" style="width:60px;" value="0.00 %"></td>
<td style="width:60px;"><input type="text" style="width:90px;" value="6,866"></td>
</tr>
</tbody>
</table>
I need to select an xpath for input field according to e.g. "Trend Factor" column.
My variant which I wrote doesn't work:
//table[#id='FinancialsGrid']/tbody/tr/td/input[count(//table/thead/tr/th[.='Trend Factor'])]
Table view:
Here is the XPath
(//table[#id='FinancialsGrid']//input)[count(//tr/th)-index-of(//tr/th, //tr/th[text()='Trend Factor']) + 1]
or another one without index-of() function (for Firebug):
(//table[#id='FinancialsGrid']//input)[count(//tr/th)-count(//tr/th[text()='Trend Factor']/preceding-sibling::*)]
Will grab required input node, where:
count(//tr/th) is count of columns
index-of(//tr/th, //tr/th[text()='Trend Factor']) - current number of column
(//table[#id='FinancialsGrid']//input) - sequence of input nodes.
So we calculating position of input node and grubbing node from sequence.

tfooter doesn't validate for xhtml?

I had my webpage validated for xhtml transitional till I added this table (see below). Since then it doesn't validate and says "
document type does not allow element "tfoot" here <tfoot>
The element named above was found in a context where it is not allowed. This could mean that you have incorrectly nested elements -- such as a "style" element in the "body" section instead of inside "head" -- or two elements that overlap (which is not allowed).
One common cause for this error is the use of XHTML syntax in HTML documents. Due to HTML's rules of implicitly closed elements, this error can create cascading effects. For instance, using XHTML's "self-closing" tags for "meta" and "link" in the "head" section of a HTML document may cause the parser to infer the end of the "head" section and the beginning of the "body" section (where "link" and "meta" are not allowed; hence the reported error)."
Any ideas as what is happening? I checked for any opened and not closed tags but did not find any so I don't know what else is wrong.
<table>
<caption>
My first table, Anna
</caption>
<thead>
<tr>
<th>
June
</th>
<th>
July
</th>
<th>
August
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
Data 1
</td>
<td>
Data 2
</td>
<td>
Data 3
</td>
<td>
Data 4
</td>
</tr>
<tr>
<td>
Data a
</td>
<td>
Date b
</td>
<td>
Data c
</td>
<td>
Data d
</td>
</tr>
<tfoot>
<tr>
<td>
Result1
</td>
</tr>
</tfoot>
</tbody>
</table>
You've got the <tfoot> at the end of the table. It should be between the <thead> and the <tbody>. It will appear at the bottom, but it's coded at the top. One of the original ideas is that as a large table loaded, the heading and footer would be visible quickly, with the rest filling in (esp. useful if the body was scrollable between them). It hasn't quite worked out like that in practice, but it does make more sense if you know that.
In the DTD it lists:
<!ELEMENT table (caption?, (col*|colgroup*), thead?, tfoot?, (tbody+|tr+))>
That is, optional caption, then zero-or-more col or colgroup, then optional thead, then optional tfoot, then at least one tbody or tr.
UPDATE: Note that HTML 5 now allows one to put the <tfoot> at the end of the table, instead of before the first <tbody> (or the first <tr> that isn't in a <thead>, <tfoot> or <tbody> and hence in a single implicit <tbody>). As such the code in the question would now be considered valid. The older approach is also still valid, and probably advisable.
The tfoot element should be outside of the tbody element, like this:
<table>
<caption>
My first table, Anna
</caption>
<thead>
<tr>
<th>
June
</th>
<th>
July
</th>
<th>
August
</th>
</tr>
</thead>
<tfoot>
<tr>
<td>
Result1
</td>
</tr>
</tfoot>
<tbody>
<tr>
<td>
Data 1
</td>
<td>
Data 2
</td>
<td>
Data 3
</td>
<td>
Data 4
</td>
</tr>
<tr>
<td>
Data a
</td>
<td>
Date b
</td>
<td>
Data c
</td>
<td>
Data d
</td>
</tr>
</tbody>
Here is a small example of the correct nesting for those who need it.
<table>
<caption></caption>
<thead>
<tr>
<th></th>
</tr>
</thead>
<tfoot>
<tr>
<td></td>
</tr>
</tfoot>
<tbody>
<tr>
<td></td>
</tr>
</tbody>
</table>

Resources