Thymeleafでth:ifとth:insertを組み合わせて使う際の注意


th:if → th:insertの順で動作させたい

何度も同じ失敗をしてしまうので、戒めを兼ねて記事に残しておくこととする。

失敗事例

例えば、価格が存在する場合のみ、特定のhtmlをinsertしたいというケースの場合、

ついつい以下のような記述をしてしまう。

productList.html
<!-- 価格が空でない場合、insertする --> 
<th:block th:if="${!#strings.isEmpty(price)}" th:insert="insert.html::product">
</th:block>
insert.html
<div th:fragment="product">
 <dt>価格</dt>
 <dd th:text="${price}"></dd>
</div>

しかし、この場合はth:insertth:ifの順で評価されてしまう為、意図した動作にならない。

priceに対してisEmptyで空かチェックしているが、空かどうか関係なしにth:insertが実行されてしまう。

属性の読み込み順については公式に記載のとおり、フラグメントのインクルードが1番最初に実行される。

対処方法

無理にth:ifth:insertを1行で書かず、分けて記述すれば良い。

productList.html
<!-- 価格が空でない場合、insertする --> 
<th:block th:if="${!#strings.isEmpty(price)}">
  <th:block  th:insert="insert.html::product"></th:block>
</th:block>

今回はth:insertを例にあげているが、th:replaceth:eachの場合も、

th:ifより優先的に評価されるため、1行で組み合わせて利用する場合に注意が必要となる。

その他にも、意図した動作にならない場合は、属性の評価順についてThymeleafの公式ページから確認可能なため、

評価の順番に認識違いがないか確認すると良い。