10

I am writing a template which should render list of employees. Employees are passed to Thymeleaf in form of list of departments where each department has its own list of employees.

As my task is to display them all - the problem is to handle continous numeration. Each employee should appear as a row with next number.

Following attempt allows to index employees of given department, with new numeration per department:

<table th:each="department, depStatus : departmentList">
    <tr th:each="employee, empStatus : department.employees">
        <td th:inline="text">[[${empStatus.index+1}]]</td>

But my point is to keep continuous numeration through all departments, just like this:

1. Employee A from Dept X
2. Employee B from Dept X
3. Employee C from Dept Y

I know I can make this structure flat at server side, but I cannot believe that it is the only way.

I have also tried to intruduce local variable with th:with="idx = 0" and then increment it somewhere with th:with="idx = ${idx} + 1, but this simply overrides outter idx value.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Maciej Dobrowolski
  • 11,561
  • 5
  • 45
  • 67
  • Im not really into this, but couldnt that explanation help a little bit? http://forum.thymeleaf.org/Simple-Counter-with-defined-variable-td4026976.html. Seems like the owner of the question tried the same as you with th:with and gets the answer, why its not possible and how he need to handle this. – NDY Mar 04 '15 at 11:32

4 Answers4

4

What you trying to achieve is to update a local variable and have the new value be visible in a scope wider than where the update was made. That's why it contradicts with th:with definition. I think you can't avoid making some server side tweaking for example providing some flatter view of your structure as you suggested.

On the other side, a quick solution, (assuming you are not strictly towards using a table) it might be trying an ordered list while using th:blocks for the enclosing department :

<ol>
  <!--/*/ <th:block th:each="dept : ${departmentList} "> /*/-->

   <li th:each="emp : dept.employees" th:text="|${emp.name} from ${dept.name}|"></li>

  <!--/*/ </th:block> /*/-->
</ol>  
gregdim
  • 2,031
  • 13
  • 15
2
    <div th:each="department : ${departmentList}">
        <div th:each="employee : ${department.employees}">
            <div th:text="${#ids.seq ('')}"></div>
        </div>
    </div>

See docs https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#ids

Kudos to https://www.tutorialfor.com/questions-69803.htm

ptomaszek
  • 123
  • 1
  • 8
0

For any loop-related operations, you should be able make use of the iterationStatus utility

Check out the following code to display the index of the iterating item.

 <tr th:each="emp,iterStat : ${employess}">
        <td th:text="${iterStat.count}"></td>
        <td th:text="${emp.name}"></td>
        <td th:text="${emp.department}"></td>
  </tr>
0

Let's see if I understand your problem:

You have a model where employees are assigned to departments. According to your description of the problem, a department object has a list of employees assigned to it.

From what I saw, you are taking from your controller class to your vision a collection of departments.

The Thymeleaf enables the use of iteration in elements through th:each attribute, as you already know. You can slightly reduce your code performing an iteration only in the collection of employees, such as:

<table>
    <tr th:each="employee, empStatus : ${department.employees}">

NOTE: If I'm not mistaken, the result of your template will repeat the table element due to the number of departments.

That way, your code will be cleaner, and you can just focus on working with employees.


In relation to the main question on the definition of an index for each line, you can use something known as "iteration status".

I believe you already know something about it, but I'll try to explain my way, which might enlighten you something:

According to the Thymeleaf documentation, you can use a variable provided by Thymeleaf that will give you access to some information about the iteration being made. With this variable, you can gather some information with properties of which are cited in the Thymeleaf documentation (check session 6.2):

The current iteration index, starting with 0. This is the index property. The current iteration index, starting with 1. This is the count property. The total amount of elements in the iterated variable. This is the size property. The iter variable for each iteration. This is the current property. Whether the current iteration is even or odd. These are the even/odd boolean properties . Whether the current iteration is the first one. This is the first boolean property. Whether the current iteration is the last one. This is the last boolean property.

To access this variable, you need to declare it soon after the declaration of the item that represent each iteration made, as you did previously:

<tr th:each="employee, empStatus : ${department.employees}">

You can also omit the declaration of this variable and still use it. This is only possible because the Thymeleaf make this statement to you, where it takes the name given to variable representing each iteration element (in this case "employee"), and add the suffix "Stat" to it (resulting on "employeeStat").

You will have access to this variable and its internal properties only within the code fragment defined by the tag with th:each attribute.

If you know how to display rows and columns in your web application page, all you have to do is use the properties of the iteration status variable, such as:

<td th:text="${empStatus.index}"></td>

Or, if you prefer:

<td th:text="${empStatus.count}"></td>

If you have any questions, please comment and I will edit my answer to a better understanding.


EDIT

Oh, I understand only now what's your real problem, sorry.

If you want to create a list where the name of each employee to appear followed by the name of their respective department, and each list item with a different number (all ordained), then the problem is quite simple.

All you have to do at first is to go through all departments, displaying the name of the employee followed by the name of the department, as you wish. This will solve part of the problem, as this is just a simple matter of logic and use of iteration.

To make that happen regularly ordained, that is, with each record / item listed in order, you can, for example, create a local variable, one of the other resources in Thymeleaf.

To quickly learn about setting and use this type of resource, check this link: setting up a value for a variable name in thymeleaf

Or you can check the documentation of Thymeleaf (Session 9): http://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf.html#local-variables

After creating your variable, try to use it as a counter, where it will be incremented for each record listed.

I hope this is helpful and solve your problem. If that does not work, please comment again and I will try another solution. Likewise, if this is not really your question, please comment also.

NOTE: Again I ask you to be careful in your loop structure. You may be creating a repeating structure that create multiple table structures in HTML code, which I believe not be what you want. Also, make sure to check if you are performing arithmetic operations correctly. I believe that your increment operation must be within the braces {}, and not out of them.


EDIT 2

I searched all over the place in order to do this ... But unfortunately I could only find this:

Counters in Loops in Thymeleaf

You can find more about this in the Thymeleaf documentation (Appendix B - Numbers). This is a valid way to do a loop with Thymeleaf. However, it is difficult to make a nested loop because we work in Thymeleaf with attributes, and not with tags / HTML elements. In case, you would create a new line only within a nested loop, something that is not possible. Maybe you can try to use the "th:each" attribute twice, in the same "tr" tag, such as:

<tr th:each="" th:each"">
</tr>

Although I believe this will not work too...

I really apologize, Maciej, as this is not a final answer, and so, not really helpfull. However, I ask you to stop just a minute and try to review your web application. Just think, you are wanting to design a table, ordering things, listing all with numbers. Would it not be better to do this in Java code? Moreover, would not you try to do this in SQL? Would not you rather get sorted results of a database with SQL? Realize that you are making an organization work here, where each employee in each department would be listed, with departments as order.

You see, I'm not saying that you are doing it wrong, but under the circumstances, and if we stop to analyze, we developers usually get ordered results from the business layer of an application, and we let the view layer responsible for only display them.

If this is not possible in your application, and the link that I sent you now can not direct you to solve your problem, then I'm terribly sorry, but I can not do anything else. Maybe it's time to you ask this in Thymeleaf forum where its developers may probably help you (probably):

http://forum.thymeleaf.org/General-Usage-f2234430.html

I sincerely hope you can succeed in your problem, solving it. And if you do, please, I kindly ask you to share your solution with everyone here, since many people may one day end up facing the same situation.

Até depois, e boa sorte amigo.

Community
  • 1
  • 1
Loa
  • 2,117
  • 3
  • 21
  • 45
  • Please note that I have used *iteration status* in the code in my question, I really know what is this for and how it works and so on and so on. I have now updated my question with example of what I am looking for. Note that there are two **nested collections** and what I am looking for is *continous* numeration of them. – Maciej Dobrowolski Mar 05 '15 at 22:59
  • I apologize, I had not read the final part of your edittion. I belive that the plus sign (+) used in the expression you used in your question will concatenate characters literals (that is, letters), not increasing numbers as you wish. Read session 4.8 from Thymeleaf documentation and try again. – Loa Mar 06 '15 at 00:09
  • I know you set a nested loop structure (as you call "nested collections"), at least that's what appears in your code. However, be careful in the way you did it. If you want to make a table with records, repeat only the rows in HTML code, not the table structure itself. Unless you want to create different table structures, don't do this: As it will repeat your table element equals the number of department records.
    – Loa Mar 06 '15 at 00:49
  • Last paragraph of my question is an attempt to do it with a local variable (using `th:with`). Unfortunately, it does not work well for when incrementing, it looks like declared variable was overriden only in a "local scope" (when iteration over inner collection ends, the variable' value becomes restored to original value - the one before iteration started). – Maciej Dobrowolski Mar 06 '15 at 08:25
  • Sorry if I ask, but you would not be doing it wrong? I mean, according to your last paragraph, you are declaring the same variable twice. The attribute "th:with" is taken as a spot for declaration, rather than processing or changing variable values already declared. Maybe you should declare the variable at one point, and work with it in another. For this, try to declare your variable with "with" attribute, and within its scope (inside the element) use the variable expression ($ {}) at some point to change its value. Please, try it and if possible, give me feedback. :) – Loa Mar 06 '15 at 18:57
  • Can you give me an example of changing value using variable expression (`${}`)? As far as I know it is 'read-only' - what means that variable expression cannot modify anything. – Maciej Dobrowolski Mar 06 '15 at 23:45