javascriptjavahtmlthymeleaf

Thymeleaf does not display all objects of my iterator


I am studying thymeleaf recently and I need a little help for a college project. Basically I have to apply the iterator pattern design to iterate on a list of objects and then print them on video on my website. I created my own iterator but however when I try to iterate with thymeleaf only the first element of the list is printed, the others are ignored. The code for my iterator is:

public class ConcreteIterator<T> implements MyIterator<T> {
    private List<T> list;
    private int index;

    public ConcreteIterator(List<T> list) {
        this.list = list;
        this.index = 0;
    }

    @Override
    public boolean hasNext() {
        return index < list.size();
    }

    @Override
    public T next() {
        if (hasNext()) {
            T item = list.get(index);
            index++;
            return item;
        } else {
            throw new IndexOutOfBoundsException("No items left!");
        }
    }
}

Il codice thymeleaf è, invece, il seguente:

<div th:while="${gameIterator.hasNext()}">
      <div th:text="${gameIterator.getCurrent().getName()}"></div>
      <div th:text="${gameIterator.getCurrent().getDescription()}"></div>
      <th:block th:width="${gameIterator.next()}"></th:block>
</div>

I solved it this way and now print the whole list:

<div th:each="i : ${#numbers.sequence(1, size)}">

    <div th:text="${gameIterator.getCurrent().getName()}"></div>
    <div th:text="${gameIterator.getCurrent().getDescription()}"></div>

    <div th:if="${gameIterator.hasNext()}">
        <th:block th:width="${gameIterator.next()}"></th:block>
    </div>

</div>

However it is a very forced method and I would like, if I could, to do it with just using the while as in the code above (alternatively I could also use javasccript, but I don’t know how to get the iterator in the javascript script to iterate). Thanks to anyone who will help me or give me a tip!


Solution

  • If possible (if you are using Iterable/Iterator provided by the JDK and have access to the Iterable), try using th:each with the Iterable instead of directly using the Iterator:

    <div th:each="current:${gameIterable}">
          <div th:text="${current.getName()}"></div>
          <div th:text="${current.getDescription()}"></div>
    </div>
    

    However, if this is not possible, you can use th:with:

    <div th:while="${gameIterator.hasNext()}">
        <th:block th:with="current=${gameIterator.next()}">
          <div th:text="${current.getName()}"></div>
          <div th:text="${current.getDescription()}"></div>
        </th:block>
    </div>
    

    This assigns the value returned by Iterator#next to a variable (current) and then uses that variable as needed.

    If you need to iterate over it multiple times, you might want to put the elements in a List which you can then iterate over multiple times. You can do something like this in your controller:

    Iterable<YourClass> gameIterable = whateverGetsYourIterable();
    List<YourClass> gameList = new ArrayList<>();
    gameIterable.forEach(gameList::add);
    model.addAttribute("gameList",gameList)
    

    and then use th:each in your Thymeleaf code.