Thymeleafのth:eachの使い方!ループ回数やindexなどの繰り返し処理を学ぼう
生徒
「Thymeleafで複数のデータを表示する方法ってありますか?」
先生
「はい、Thymeleafではth:each属性を使って、リストや配列のデータを簡単にループ表示できます。」
生徒
「どうやって使うんですか?」
先生
「では、基本的な使い方を説明していきましょう!」
1. th:each属性とは?
Thymeleafのth:each属性は、HTML内でループを作成し、リストや配列の要素を順番に表示するために使用します。例えば、商品一覧やユーザーリストをページに表示したいときに役立ちます。
基本的な構文は次の通りです:
<ul>
<li th:each="item : ${items}">
[[${item}]]
</li>
</ul>
このコードでは、${items}にリストがバインドされていると、各要素がitemとしてループ内に展開されます。
2. 実際の例で学ぶth:eachの使い方
それでは、具体的なサンプルコードを見てみましょう。以下は、商品リストを表示する例です:
<table class="table table-striped">
<thead>
<tr>
<th>商品名</th>
<th>価格</th>
</tr>
</thead>
<tbody>
<tr th:each="product : ${productList}">
<td>[[${product.name}]]</td>
<td>[[${product.price}]]円</td>
</tr>
</tbody>
</table>
この例では、${productList}に商品データのリストが入っていると、productオブジェクトのnameとpriceの情報がテーブルとして表示されます。
3. th:eachの変数を使いこなそう
th:each属性を使うと、インデックス情報や偶数・奇数行の識別など、便利な変数も利用できます:
<tr th:each="product, iterStat : ${productList}" th:class="${iterStat.odd ? 'table-secondary' : ''}">
<td>[[${iterStat.index + 1}]]</td> <!-- インデックス (0から始まるので+1) -->
<td>[[${product.name}]]</td>
<td>[[${product.price}]]円</td>
</tr>
このように、iterStatを使用することでインデックスや行の状態(奇数・偶数)を管理できます。
4. th:eachを使うときの注意点
繰り返し処理を行う際、Nullのリストや空のリストに注意が必要です。th:eachで使用するオブジェクトがnullの場合、例外が発生する可能性があります。そのため、事前にデータがあるか確認するか、Thymeleafのth:ifを組み合わせることで安全に表示できます:
<div th:if="${productList != null && !productList.isEmpty()}">
<!-- th:eachによるループ -->
</div>
5. ループ回数を制御する(上位N件・ページング)
「上位N件だけ表示したい」「ページングしたい」ときは、subListやth:withで範囲を切ってからth:eachに渡すのがシンプルです。SEO的にも一覧の表示量を抑えて表示速度を高めるのは有効です。
<!-- 上位5件のみ -->
<ul>
<li th:each="p : ${productList.subList(0, productList.size() >= 5 ? 5 : productList.size())}">
[[${p.name}]] / [[${p.price}]]円
</li>
</ul>
<!-- 簡易ページング:クエリ ?page=0&size=10 を想定(endは排他的) -->
<div th:with="
page=${param.page ?: 0},
size=${param.size ?: 10},
start=${page * size},
end=${start + size},
last=${productList.size()},
from=${start < last ? start : last},
to=${end <= last ? end : last}
">
<table>
<tr th:each="p,st : ${productList.subList(from, to)}">
<td>[[${from + st.index + 1}]]</td>
<td>[[${p.name}]]</td>
<td>[[${p.price}]]円</td>
</tr>
</table>
</div>
6. 反復ステータスを極める(index/count/size/odd・even/first・last)
th:each="item, stat : ${list}"の第2変数statには便利なプロパティが揃っています。行番号や奇数偶数、先頭末尾を使って装飾・区切り・No.付与ができます。
<tr th:each="product, stat : ${productList}"
th:class="${stat.odd} ? 'table-secondary' : ''">
<td>No. [[${stat.count}]] / 全[[${stat.size}]]件</td> <!-- countは1始まり -->
<td>[[${product.name}]]</td>
<td>[[${product.price}]]円
<span th:if="${stat.first}" class="badge bg-info ms-2">NEW</span>
<span th:if="${stat.last}" class="badge bg-secondary ms-1">LAST</span>
</td>
</tr>
<!-- 区切り文字の制御:最後のカンマを出さない -->
<span th:each="tag, s : ${product.tags}">
[[${tag}]]<span th:if="${!s.last}">, </span>
</span>
7. ネストしたループとMapの反復(親子リスト/key・value)
カテゴリごとに商品を出すなどの「親子リスト」や、Mapのkey/valueを回す方法です。親ループのstatで章番号を付けるなど、構造化された一覧に強いです。
<div th:each="cat, cStat : ${categoryList}" class="mb-3">
<h4>[[${cStat.count}]]. [[${cat.name}]]</h4>
<ol>
<li th:each="p, pStat : ${cat.products}">
[[${cStat.count}]].[[${pStat.count}]] [[${p.name}]]([[${p.price}]]円)
</li>
</ol>
</div>
<!-- Mapをループ:エントリ(key/value) -->
<table class="table">
<tr><th>キー</th><th>値</th></tr>
<tr th:each="e : ${priceMap}">
<td>[[${e.key}]]</td>
<td>[[${e.value}]]</td>
</tr>
</table>
大きなコレクションはページングや「上位N件」に分割し、表示速度と可読性を両立しましょう(「Thymeleaf th:each ページング」「index 行番号」などの検索ニーズにもマッチ)。
まとめ
今回は、Thymeleafのth:each属性を使った繰り返し処理について詳しく解説しました。th:eachを使用することで、HTML内でのループが簡単に実現でき、Webアプリケーションにおいてリストデータや配列を動的に表示する場面で非常に役立つことを学びました。また、iterStatを用いることでインデックス情報や偶数・奇数の識別など、便利な機能も活用できる点を紹介しました。さらに、データがnullや空のリストである際の対処方法として、th:ifとの併用も有効であることを示しました。
繰り返し処理を活用することで、ユーザビリティの高いページを作成でき、エラーの発生を防ぐために事前のデータチェックも欠かせません。これらのポイントを理解しておくと、Web開発の幅が広がり、動的なコンテンツ生成が一層効率化されます。
以下は、簡単なサンプルプログラムを再度示したものです:
<table class="table table-striped">
<thead>
<tr>
<th>#</th>
<th>商品名</th>
<th>価格</th>
</tr>
</thead>
<tbody>
<tr th:each="product, iterStat : ${productList}" th:class="${iterStat.odd ? 'table-secondary' : ''}">
<td>[[${iterStat.index + 1}]]</td> <!-- インデックス (0から始まるので+1) -->
<td>[[${product.name}]]</td>
<td>[[${product.price}]]円</td>
</tr>
</tbody>
</table>
生徒
「Thymeleafのth:eachを使った繰り返し処理について、よく分かりました。インデックスや行のスタイルを簡単にコントロールできるのが便利ですね。」
先生
「そうですね。iterStatなどの変数を活用すれば、さらに細かな制御が可能になります。実際の開発でも試してみてください。」
生徒
「はい、ありがとうございます!th:ifを使ってデータの有無をチェックする方法も覚えておきます。」