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:insert
→ th:if
の順で評価されてしまう為、意図した動作にならない。
priceに対してisEmptyで空かチェックしているが、空かどうか関係なしにth:insert
が実行されてしまう。
属性の読み込み順については公式に記載のとおり、フラグメントのインクルードが1番最初に実行される。
対処方法
無理にth:if
とth: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:replace
やth:each
の場合も、
th:if
より優先的に評価されるため、1行で組み合わせて利用する場合に注意が必要となる。
その他にも、意図した動作にならない場合は、属性の評価順についてThymeleafの公式ページから確認可能なため、
評価の順番に認識違いがないか確認すると良い。