Java/Spring Boot web app here using Thymeleaf as the templating engine.
My bean:
public class InventoryItem {
private String modelNumber;
private String name;
// getters, setters and ctors omitted for brevity
}
My Spring controller:
#Controller
#RequestMapping("/inventory")
public class InventoryController {
#GetMapping("/{inventoryId}")
public String viewInventory(#PathVariable("inventoryId") String inventoryId, Model model) {
List<InventoryItem> inventory = getSomehow(inventoryId);
model.addAttribute("inventory", inventory);
return "inventory";
}
}
And a snippet from the inventory.html file that Thymeleaf must template:
<div class="col-md-4 mt-5">
<div class="panel-body">Inventory Items</div>
<ul>
<li th:each="item :${inventory}" th:text="${item.name}"></li>
</ul>
</div>
At runtime this produces a nice unordered list of inventory item names.
What I want now is to make this an unordered list of hyperlinks (<a/>) such that the rendered HTML looks like so:
<ul>
<li>Goose</li>
<li>Duck</li>
<!-- etc. -->
</ul>
Where 12345 and 23456 are InventoryItem#modelNumbers and where Goose and Duck are InventoryItem#names. I've asked the Google Gods high and low and cannot find a working example of using Thymeleaf to render a list (ordered/unordered alike) of hyperlinks. Any ideas?
Something like this would work ...
<div class="col-md-4 mt-5">
<div class="panel-body">Inventory Items</div>
<ul>
<li th:each="item :${inventory}">
<a th:href="#{/inventoryDetails/{modelNumber}(modelNumber=${item.modelNumber})}" th:text="${item.name}">Goose</a>
</li>
</ul>
</div>
If you would like to get more information on how to work with Link URLs, follow Thymeleaf documentation.
Related
I have the following thymeleaf template
<!doctype html>
<html lang="nl" xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments::head(title='Film zoeken')">
<title>Film zoeken</title>
</head>
<body>
<nav th:replace="fragments::menu"></nav>
<form method="get" th:object="${zoekForm}" th:action="#{/film/zoeken}">
<label>
Nummer:
</label>
<span th:errors="*{id}"></span>
<input th:field="*{id}" type="number" autofocus required min="1">
<button>Zoeken</button>
</form>
<th:block th:if="${film}" th:object="${film}">
<dl>
<dt>Titel</dt>
<dd th:text="*{title}"></dd>
<dt>Regisseur</dt>
<dd th:text="*{regisseur}"></dd>
<dt>Uitgekomen op</dt>
<dd th:text="*{releaseDate}"></dd>
<dt>Karakters</dt>
<dd th:each="karakter : *{karakters}" th:text="${karakter}"></dd>
</dl>
<form th:if="not ${score}" th:object="${scoreForm}" method="post"
th:action="#{/film/{id}/score(id=${param.id})}">
<label>
Score:
<span th:errors="*{score}"></span>
<input th:field="*{score}" type="number" required min="1" max="10">
</label>
<button>Bewaren</button>
</form>
<div th:if="${score}">
Je score voor deze film is <strong th:text="${score.score}"></strong>
</div>
</th:block>
</body>
</html>
I have two #GetMapping methods and then the final #PostMapping.
The first one do a modelAndView.addObject(new ZoekForm(null));, so it shows only the first form.
Then, the second getmapping do a thing with the content (it shows the film data) and then it has a
modelAndView.addObject("scoreForm", new ScoreForm(null));.
So far the template shows 1) search form for a movie, 2) the film data and finally a field to give the movie a score.
I need to give a score (hit the button from the second form) and show the div
<div th:if="${score}">
Je score voor deze film is <strong th:text="${score.score}"></strong>
</div>
but the website must keep showing the film data. Now, when I hit that score button, all goes away.
It seems like the th:if=${film} is not happening. Clues?
(I assume also that the score object needs to be passed in the post, because if I look up again the same movie, I must be unable to give it a score).
Thymeleaf doesn't create objects for you. You need to pass it the object in your controller. You can either do it in every controller method that returns this template page or just use #ModelAttribute (place it as a method to your controller)
#ModelAttribute("film")
public Film methodNameDoesntMatter() {
return new Film();
}
This will occur on every page reload, so Film object is always new. Make sure there are getters/setters and no arg constructor defined - this is important for thymleaf
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.
Model has Map(String,Integer), this map displayed on page in checkboxes like:
<ul>
<li th:each="item : ${map}">
<input type="checkbox" th:checked="${item.value} == 1" th:id="${item.key}"/>
<label th:for="${item.key}" th:text="${item.key}"/>
</li>
</ul>
How should i submit checkboxes state changes?
If you are using Spring MVC as your application and Thymeleaf as your view engine please check out this section on dynamic forms and working with them:
http://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html#dynamic-fields
Essentially what you want to do is have an object that would have a Map as a variable within it, which would then bind all your inputs against when it hits the controller.
e.g.
public class MyObject {
Map<String, Integer> myMap;
// getters and setters
}
I have a Spring + Thymeleaf project. I have a fragment for the header part and some pages which include the header.
Below is the (essential part of) the header fragment. As you can see it includes the activeUserWorkgroup model object
dashboard-header.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<body>
<header th:fragment="dashboard-header" class="header">
....
<div class="navbar-right">
<ul class="nav navbar-nav">
<li class="dropdown notifications-menu">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<span class="user-label" style="margin-left:5px;"
th:text="${activeUserWorkgroup.getWorkgroupLabel()}">
</span>
</a>
</li>
</ul>
</div>
</nav>
</header>
</body>
</html>
In every Spring view where I need the header fragment I add the line
<div th:replace="fragments/dashboard-header :: dashboard-header"></div>
The problem is that in every Controller of every View in which I need this header, I have to give the proper value to the activeUserWorkgroup model object. This is both uncomfortable and error prone.
Is there any way to let Spring give the proper model value to the activeUserWorkgroup object without having to write the code in every Controller?
Thank you
This probably what you are looking for. What I would do is create controller that return just the Model object activeUseWorkgroup. Then have all the other controllers extend it.
#Controller
public ControllerA
{
#ModelAttribute("activeUserWorkgroup")
public Object getActiveUserWorkgroup()
{
return new Object();
}
}
#Controller
public ControllerB extends ControllerA
{
}
Maybe is better to create a ControllerAdvice, read the documentation at this link http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/ControllerAdvice.html
#ControllerAdvice
public class GlobalControllerAdvice extends ResponseEntityExceptionHandler {
#ModelAttribute("activeUserWorkgroup ")
public String getActiveWorkgroup() {
//YOUR CODE
}
}
Is it possible in Apache's velocity template engine to partially parse html template?
For example:
If I have template like this:
<div class="container">
<div id="section1">Some content of section 1....</div>
<div id="section2">Some content of section 2....</div>
</div>
I would like to parse only contents of section1 div. How can I accomplish this?
I'm using Spring MVC 3.0 with this.
There is no direct way to achieve this, but you can use variables to define parts and assist in partial parsing:
<div class="container">
#if ($model.part1)
<div id="section1">Some content of section 1....</div>
#end
#if (model.part2)
<div id="section2">Some content of section 2....</div>
#end
</div>
where model
public class PartialDef {
boolean part1;
boolean part2;
//setters and getters
}
So based on which part of html you want to include/exclude, define and turn-On/Off variables accordingly.