Nested Thymeleaf Templates in Spring

3.7k views Asked by At

Short version

How is one supposed to make nested templates in Thymeleaf when using Spring? It appears asterisk notation is not supported ("*{mailingAddress}") inside th:object attributes in Spring. Is there a work-around / different tag to use?

Long version

For example, let's say I have these classes:

class Address { String street; }
class Person { Address mailingAddress; Address shippingAddress; }
class Order { int orderNo; Person customer; } 

So I make an address.html Thymeleaf template:

<span th:text="*{street}"></span>

We test it with a sample Address. Looks good.

and I make a person.html Thymeleaf template that references the address like so:

<span th:text="*{firstName}"></span>
<span th:object="${person.shippingAddress}">
    <span th:include="fragments/address :: address"></span>
</span>

And we test it with an example person. I could even reference the same template and set the context to be the ${person.mailingAddress}. So far so good.

Now let's make our Order template. Only, hey, wait. Earlier, in our person.html file we said ${person.shippingAddress} but now we need it to say ${order.customer.shippingAddress}. If I were not using Spring I'd put the following into person.html:

<span th:text="*{firstName}"></span>
<span th:object="*{shippingAddress}">
    <span th:include="fragments/address :: address"></span>
</span>

That way, no matter what my path to getting here all I have to care about is that my current context has a shippingAddress. I could then use person.html directly as well as within my order.html template.

Unfortunately I am in Spring, so I get the following exception:

org.thymeleaf.exceptions.TemplateProcessingException: 
    The expression used for object selection is *{shippingAddress},
    which is not valid: only variable expressions (${...}) are
    allowed in 'th:object' attributes in Spring-enabled environments. 
    (include:510)
at org.thymeleaf.spring4.processor.attr.SpringObjectAttrProcessor.validateSelectionValue(SpringObjectAttrProcessor.java:73)
at org.thymeleaf.standard.processor.attr.AbstractStandardSelectionAttrProcessor.getNewSelectionTarget(AbstractStandardSelectionAttrProcessor.java:69)
at org.thymeleaf.processor.attr.AbstractSelectionTargetAttrProcessor.processAttribute(AbstractSelectionTargetAttrProcessor.java:61)

To move forward I must duplicate all my nested templates. In this example, I would have one person.html with th:object="${person.mailingAddress}" calling to address.html, and a duplicate of person.html called orderCustomer.html where we change the line to th:object="${order.customer.mailingAddress}", but is otherwise identical.

Is there a work-around out there that would let me re-use templates?

1

There are 1 answers

0
Faraj Farook On BEST ANSWER

You can report a bug to the thymeleaf developers in github, or fork the project to add this functionality and convince the Daniel Fernández to accept it.

https://github.com/thymeleaf/thymeleaf/issues

Or else, he is available in StackOverflow. You can simply send him a message about the posibility of integrating this functionality

https://stackoverflow.com/users/550664/daniel-fern%C3%A1ndez

apart from that there is nothing much we can do rather to stick with the approach of putting th:object="${person.mailingAddress}" and th:object="${order.customer.mailingAddress}" outside each import.