Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing bean field to th:field in Thymeleaf fragment

I'm trying to refactor our Thymeleaf code that have a lot of copy-paste. The general idea is we have something like this:

<form th:object="${createForm}">
  <div><input type="text" th:field="*{first}"/> <!-- some boilerplate code --></div>
  <div><input type="text" th:field="*{second}"/> <!-- some boilerplate code --></div>
  <div><input type="text" th:field="*{third}"/> <!-- some boilerplate code --></div>
  <div><input type="text" th:field="*{fourth}"/> <!-- some boilerplate code --></div>
 </form>

and I want to refactor the fragment

  <input type="text" th:field="*{first}"/> <!-- some boilerplate code -->

to a separate file as it is a lot of copy paste (there is quite some HTML in the boilerplate code section).


My first approach was to do something like this:

<form th:object="${createForm}">
  <div th:replace="fragments/input :: input(*{first}" />
  <div th:replace="fragments/input :: input(*{second}" />
  <div th:replace="fragments/input :: input(*{third}" />
  <div th:replace="fragments/input :: input(*{fourth}" />
 </form>

and then have a fragments/input.html file

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
</head>
<body>
<div th:fragment="input(field)">
    <input th:field="${field}"/> <!-- some boilerplate code -->
</div>
</body>
</html>

But, once compiled/deployed, I get error

java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'field' available as request attribute

Anyone an idea how to solve this? The question is to reduce code copy-paste while retaining the benefit of having th:field.


I also tried use th:with like this

<div th:width="field=*{first}" th:replace="fragments/smallslider :: input()" />

and fragment

<div th:fragment="input()">
    <input th:field="${field}"/> <!-- some boilerplate code -->
</div>

but that did neither produce error nor generate HTML.

like image 537
Ondrej Skalicka Avatar asked Mar 10 '16 16:03

Ondrej Skalicka


2 Answers

I solved this in similar way as @Wilson did.

Fragment:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head></head>
<body>
    <div th:fragment="input(fieldName)">
        <input th:field="*{__${fieldName}__}" type="text">
    </div>
</body>
</html>

Calling:

<form th:object="${createForm}">
    <div th:replace="fragments/input :: input('first')" />
    <div th:replace="fragments/input :: input('second')" />
    <div th:replace="fragments/input :: input('third')" />
    <div th:replace="fragments/input :: input('fourth')" />
</form>
like image 187
Karolis Avatar answered Nov 07 '22 13:11

Karolis


you can achive this by passing the name of your bean field to the fragment like so.

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
</head>
<body>
<div th:fragment="input(fieldName, fieldValue)">
    <input th:name="${fieldName}" th:value=${fieldValue}/> <!-- some boilerplate code -->
</div>
</body>
</html>

and call it like so

<form th:object="${createForm}">
  <div th:replace="fragments/input :: input('field', *{field})" />
 </form>
like image 34
Wilson Campusano Avatar answered Nov 07 '22 13:11

Wilson Campusano