Pass Thymeleaf block content as variable to fragment - java

I'm trying to create a fragment that represents a card with custom content. I would like to do something like:
<div class="card" th:fragment="myfragment" th:utext="${content}">
</div>
And then use as
<th:block th:replace="myfragment">
<p>Some custom content that would be the value of 'content'</p>
</th:block>
This would make it a lot easier to work with bigger html that would be kinda ugly to write in an attribute. (Basically I'm looking for a similar functionality to Blade's views and slots)
EDIT:
I'm aware of fragment parameterisation but passing long and complex html code in an attribute is pretty ugly and hard to manage.
A more descriptive example would be a card where the card body is not a p but a table for example.

Soo, maybe not the best solution but I managed to get this working based on this Other SO thread and this
Example code
I've created a new dialect so I can say this:
<zms:card header="'ASD Title'">
<div th:text="${first_name}"></div>
asdasd card works asdasd
</zms:card>
And it will render this:
<div class="card shadow mb-4">
<div class="card-header py-3">
<div class="d-inline-block">
<h6 class="m-0 font-weight-bold">ASD Title</h6>
</div>
</div>
<div class="card-body">
<div>Name</div>
asdasd card works
</div>
</div>

Thymeleaf supports parameterized fragments. Here's how you can use it:
Fragment Definition:
_fragments/my_fragments.html:
<th:block th:fragment="myFragment(p1, p2, p3)">
//do sth with p1, p2, p3
</th:block>
Using it:
<th:block th:replace="_fragments/my_fragments :: myFragment(${p1}, ${p2}, ${p3} )">
</th:block>
Ref:
https://ganeshtiwaridotcomdotnp.blogspot.com/2020/09/thymeleaf-pass-parameter-to-fragment.html
https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#parameterizable-fragment-signatures
https://github.com/gtiwari333/spring-boot-web-application-seed/blob/master/main-app/src/main/resources/templates/_fragments/_utils.html

Related

How to pass an array of HashMaps to partial

I'm building an app with Java and Thymeleaf and I need to pass a HashMap to a partial. I don't want to pass it from a controller.
This is what I tried so far:
user.html
<div th:replace="partials/icons.html :: icons(icons=${ {name='user', title='User'}, {name='blog', title='Blog'} })"></div>
/partials/icons.html
<div th:fragment="icons">
<th:block th:each="icon : ${icons}">
<button th:class="'icon-' + ${icon.name}" th:text="${icon.title}"></button>
</th:block>
</div>
It gives me an error that = is unexpected. What would be the correct syntax?
EDIT: I should have clarified up-front: there is no way to do what you are trying to do with the syntax of fragment parameters. My approach below is a work-around.
Assuming you have the following object as a starting point:
public class Icon {
private String name;
private String title;
// getters and setters...
}
Assuming you then have a List of such objects, called icons...
This list is passed to your Thymeleaf renderer in the usual way. I don't use Spring, so how you do that is (I assume) through an annotation. I may be wrong - it shouldn't affect the approach below, however. In my no-Spring approach the list is added to the Thymeleaf model as map.put("icons", icons);
I have the following in my parent Thymeleaf template:
<div th:replace = "/iconsfragment.html :: icons(iconlist='icons')">
</div>
I have the following in iconsfragment.html:
<div th:fragment="icons(iconlist)">
<th:block th:each="icon : ${__${iconlist}__}">
<div th:class="'icon-' + ${icon.name}" th:text="${icon.title}"></div>
</th:block>
</div>
It uses a preprocessor __${...}__ to convert the parameter (a string) back into an iterable object.
The resulting HTML that you care about is:
<div class="icon-firstName">firstTitle</div>
<div class="icon-secondName">secondTitle</div>
This only really makes sense if you want to re-use that fragment in various different ways, of course. Otherwise just pass the ${icons} object directly to the fragment.
And my <div> example would of course need to be adapted to your <button> example.

Is it possible to include format of a thymeleaf fragment

I'm looking for a way to include the structure of a thymeleaf fragment into a page.
What i mean by that is as follows:
The fragmend defined as follows:
<div class="container" th:fragment="container">
<div class="row">
{the content of the page continues here}
</div>
</div>
The page template:
<div th:replace="fragments/main:: container">
{I can continue here for eq, <div class="col-md-5"></div>}
</div>
I dont't know if this is possible but i'm looking for a way to do this.
Due to layout dialect of Thymeleaf, this can be done by adding
<th:block layout:fragment="content"/> to desired layout and using this as parent element in your view.

Local conditional variable thymeleaf

I'm trying to rewrite without duplication something like this:
<span th:if=${userRole == 'ADMIN'} style="display:inline;"> // display property for logic only
<div> ... </div>
</span>
<span th:unless=${userRole == 'ADMIN'} style="display:none;">
<div> ... </div>
</span>
In the 2nd case we have the same code, just hidden. This way I have duplicated code. It would be better to have a variable change it's value to either "none" or visible" and use that on a single tag.
How can I do it without duplication, implementing the following logic:
$variable = "display: none;"
th:if=${userRole == 'ADMIN'} $variable="display: visible"
<span style="display: $variable;">
<div> ... </div>
</span>
You can use a ternary operator (? :) to do it in one line without duplication.
th:style="${userRole} == 'ADMIN' ? 'display:inline' : 'display:none'"
I hope this is what you are looking for.

Display a string that contains HTML in Thymeleaf template

How can I display a string that contains HTML tags in Thymeleaf?
So this piece of code:
<div th:each="content : ${cmsContent}">
<div class="panel-body" sec:authorize="hasRole('ROLE_ADMIN')">
<div th:switch="${content.reference}">
<div th:case="'home.admin'">
<p th:text="${content.text}"></p>
</div>
</div>
</div>
//More code....
And at this line of piece of code ${content.text} it literally generates this on the browser:
<p>test</p>
But I want to show this instead on the browser:
test
You can use th:utext (unescaped text) for such scenarios.
Simply change
<p th:text="${content.text}"></p>
to
<p th:utext="${content.text}"></p>
I will suggest to also have a look into documentation here to know all about using Thymeleaf.

Zkoss zhtml extra div when using appendchild?

My question is related to zkoss and dynamically added components from the Java side.
Whenever I'm using appendchild on any element (like on a Div) it always adds an extra Div as some kind of container. Why is that?
Example, here is a part of a Composer class:
...
#Wire("div#myDiv")
private Div testDiv;
...
...
Label myLabel = new Label();
myLabel.setValue("Test");
myLabel.setClass("test-label");
testDiv.appendChild(myLabel)
So instead of this:
<div id="myDiv">
<span class="test-label">
...
</span>
</div>
I get something like this:
<div id="myDiv">
<div id="hj973"> <!--this is the extra div -->
<span class="test-label">
...
</span>
</div>
</div>
In most cases this is not a problem, except when I'm trying to use the span's as a grid with float, because then of course that div shouldn't be there.
Why is this? How can I prevent it?
I don't know why there is a extra div, but you could write
test-label:parent {
...
}
in your css file so the outer div behaves the way your span
should do now and just ignore span.
If this don't help, I'll check this later, I don't have the time right now.

Categories