Thymeleaf in spring boot - spring-boot

I am trying to use an HTML template as given below and set 2 values to it dynamically.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title th:text="${title}"></title>
</head>
<body>
<div class="page-content">
<h1 th:text="|Hello ${siteCode}!|"></h1>
</div>
</body>
</html>
I used the below code to set the values.
Model model = new ExtendedModelMap();
model.addAttribute("title", site.getName());
model.addAttribute("siteCode", site.getCode());
I want to get the new html file with the values added in the template variable so that I can store the file to s3. Please help.. Thanks in advance.

Related

Spring Boot HtmlConverter set dynamic value in html file

I would like to have dynamic value in my html file which gets Convertet to a PDF file. I've got no idea how to do that.
HTML
<!doctype html>
<html lang="en">
<head>
<title>SpringHow html to pdf</title>
</head>
<body>
<div>
<h2> --> DYNAMIC VALUE HERE <-- </h2>
</div>
</body>
</html>
JAVA
HtmlConverter.convertToPdf(new File("template.html"),new File("report.pdf"));

Thymeleaf 3 (not) building layout sequentially?

I know about existance of layout dialect for Thymeleaf (https://github.com/ultraq/thymeleaf-layout-dialect), but before jumping into said dialect dating pre thymeleaf 3, I wanted to explore newer fragment expressions (introduced in TL3).
So as per docs - I can define base.html that will work almost the same way that the layout dialect allows fragments to be managed.
base.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:fragment="base(title, links, content)">
<title th:replace="${title}"></title>
<link rel="stylesheet" type="text/css" media="all" href="/css/main.css" />
<th:block th:replace="${links}"></th:block>
</head>
<body>
<header th:replace="~{header :: header}"></header>
<div th:replace="${content}"></div>
<footer th:replace="~{footer::footer}"></footer>
</body>
</html>
...but then when I use this in my home.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="base::base(~{::title}, ~{::link}, ~{::content})">
<title th:text="#{home.title}"></title>
<link rel="stylesheet" th:href="test">
<link rel="stylesheet" th:href="test1">
<link rel="stylesheet" th:href="test2">
</head>
<body>
<div th:fragment="content">
<span>TEST CONTENT</span>
</div>
</body>
</html>
...it acts like home.html only evaluates itself and arguments it passes to base.html because this is product:
<!DOCTYPE html>
<html>
<head>
<title>My home page</title>
<link rel="stylesheet" type="text/css" media="all" href="/css/main.css" />
<link rel="stylesheet" href="test"><link rel="stylesheet" href="test1"><link rel="stylesheet" href="test2">
</head>
<body>
<div>
<span>TEST CONTENT</span>
</div>
</body>
</html>
As you can see, title is evaluated in home.html and passed to base.html, same goes for 3 links I provided in home.html. Also content gets passed and placed in proper place. What is missing? Everything that is not argument of base.html fragment. Thymeleaf ignores evaluating my header and footer and just removes them.
Let me just note that If I were to place header/footer in home.html inside content they will be evaluated like they should - from header.html with selector header: "~{header :: header}".
Am I missing something crucial as to how this whole thing is supposed to work? What's the point of being able to define fragments that will work as layout if they can't evaluate themselves and need everything passed from "child file (caller)"?
It seems to me you mixed fragments and replacements together. The head replacement works well because you declared it correctly. But why did you declare a th:replace attribute in base.html like
<header th:replace="~{header :: header}"></header>? It is not within a fragment, not a parameter, therefore it must be replaced from somewhere.
As far as I understand you expect fragments in base.html and replacements in home.html. Then make both the header and footer fragments and declare corresponding th:replace tags in home.html.
<div th:replace="${content}"></div>
This also doesn't work because it is not within a th:fragment tag.
The bottom line: fix the hierarchy of tags and the logic of replacement.
Like Xaltotun pointed out - I needed to fix my stuff.
I've placed base(args...) in header so my passed fragments werent visible in body, thus everything failed.
Let me just add some code:
Layout.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" th:fragment="layout(content, title, meta)">
<head>
<title th:text="${title}">Default Title</title>
<link rel="stylesheet" type="text/css" media="all" href="/css/style.css" />
<th:block th:replace="${meta}" />
</head>
<body>
<div class="viewport">
<header class="website-header">
...
</header>
<div th:replace="${content}"></div>
<th:block th:replace="staticContentTemplate :: testFragment" />
<footer class="website-footer">
...
</footer>
</div>
</body>
</html>
Home.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" th:replace="layout::layout(~{::content}, #{home.title}, ~{::meta})">
<head>
<th:block th:fragment="meta">
<link rel="stylesheet" th:href="test">
</th:block>
</head>
<body>
<div th:fragment="content">
<span>TEST CONTENT</span>
</div>
</body>
</html>
Result is as expected:
Home.html provides title, content and meta.
Layout.html gives everything else, and also copies additional template from different source staticContentTemplate :: testFragment
Tip for others: notice that I placed args in layout in this order - content since its always present, title that can be optional and meta that might not be needed - this allows us to call layout with just content: layout(~{::content}) (shorter = better).

How can I create a general page, that I can use every where inside the app using Thymleaf and Spring boot?

I'm trying to understand how use Thymeleaf, I have a structure like this:
I have a default.html that work like the most general page, I put there some inclusion like general css, bootstrap and so on.. The I replace using th:replace the footer and a navbar. I use this page as base line for all the other pages.
My problem is: how can I use this page for all the other pages?
For example if I have 2 pages, page A and B and both of them need bootstrap, the app's css and so on, I don't want write the code to include them twice, but only once. So to do that I think I have to put page A inside default.html if I want show A and B in the other case.
At least, I done in this way using JSP.
How can I do it? Is it possible using Thymeleaf?
I tried to do somenthig like that but id doesn't work
DEFAULT.HTML
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<title th:text="#{application_name}"></title>
<link rel="icon" type="image/x-icon" th:href="#{/static/favicon.ico}"/>
<script th:src="#{/webjars/jquery/jquery.min.js}"></script>
<script th:src="#{/webjars/bootstrap/js/bootstrap.min.js}"></script>
<link rel="stylesheet" th:href="#{/webjars/bootstrap/css/bootstrap.min.css}"/>
<link rel="stylesheet" th:href="#{/css/mio.css}"/>
<link rel="stylesheet" th:href="#{/webjars/font-awesome/css/font-awesome.min.css}"/>
</head>
<body>
<div th:replace="~{fragments/header :: header}"></div>
<div class="container">
<div layout:fragment="content">
<p>Your page content goes here</p>
</div>
</div>
<div th:replace="~{fragments/footer :: footer}"></div>
</body>
</html>
It is totally possible!
We have some steps to do it with Thymeleaf:
Configurations:
1 - Include the thymeleaf layout dialect into your project:
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
<version>2.1.2</version>
</dependency>
2 - I do not know how is your webConfig, but with Spring, we have to add this configuration to template engine:
#Bean
public TemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setEnableSpringELCompiler(true);
//your templateResolver
engine.setTemplateResolver(templateResolver());
//here it is!
engine.addDialect(new LayoutDialect());
return engine;
}
The default html:
<!DOCTYPE html>
<html lang="pt-BR"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
<!-- Necessary to thymeleaf layout dialect-->
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<link rel="stylesheet" type="text/css" th:href="#{/layout/stylesheets/vendors/bootstrap.css}" />
</head>
<body>
<header>your Heder here</header>
<!--Here what you want, it gonna find the other html that contains "maincode"-->
<section layout:fragment="maincode"></section>
<footer>yourFooter</footer>
<script th:src="#{/javascript/vendors/jquery-2.2.4.min.js}"></script>
<script th:src="#{/layout/javascripts/bootstrap.min.js}"></script>
<th:block layout:fragment="javascript-extra"></th:block>
</body>
</html>
The other html:
<!DOCTYPE html>
<html lang="pt" xmlns="http://w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
<!--Tell who is the default html-->
layout:decorate="layout/defaultHtml">
<body>
<section layout:fragment="maincode">
bla bla bla
</section>
</body>
</html>
Any question, just ask!

How can I show/hide FreeMaker template FTL

I'm new to FreeMaker Template, In the below example, I want to show the <#greet person="${name}"!/> macro for 10 seconds only, then need to remove it, any idea how can I make it?
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>${title} | Kweet</title>
</head>
<body>
<#greet person="${name}"!/>
<#include "/copyright_footer.html">
</body>
</html>
<#macro greet person color="black">
<font size="+2" color="${color}">Hello ${person}!</font>
</#macro>
You can do that with JavaScript (which you put into the template). It has nothing to do FreeMarker, as that only generates the page before it's sent to the browser.

laravel #include with #section in <head>

I've a simple main layout:
<!DOCTYPE html>
<html>
<head>
<title>Title</title>
#yield('style')
</head>
<body>
#include('layouts.frontend.partials.slider')
#yield('javascript')
</body>
</html>
layouts.frontend.partials.slider
#section('style')
<link rel="stylesheet" type="text/css" href="mystyle.css">
#append
#section('javascript')
<script></script>
#append
<div class="swiper-container">
<div class="swiper-wrapper">
<div class="swiper-slide" data-swiper-autoplay="1000">Slide 1</div>
<div class="swiper-slide" data-swiper-autoplay="1000">Slide 2</div>
<div class="swiper-slide" data-swiper-autoplay="1000">Slide 3</div>
</div>
<div class="swiper-pagination"> </div>
<div class="swiper-button-prev"> </div>
<div class="swiper-button-next"> </div>
</div>
The #section('style') will be ignored while the #section('javascript') is working fine within the include file...
I've reduced both files (main and include) to a minimum and swapped the position of style and javascript without any difference
What seems to be working is to change to position from the #yield('style') to the body, like:
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>
#include('layouts.frontend.partials.slider')
#yield('javascript')
#yield('style')
</body>
Maybe it's not allowed to have #section in an include file?
What i want to archive is to have multiple partial includes with it's own css and javascript includes
Thanks
Here is another way to do, it's good because you have some flexibility.
You create a master template, put your main files
master.blade.php
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="stylesheet" href="">
#section('css')
<!-- some master css here -->
#show
</head>
<body>
#section('navbar')
#include('common.navbar')
#show
#yield('content')
#include('common.footer')
#section('js')
<!-- some js here -->
#show
</body>
</html>
The others childs extends the master, you'll have all your layout and can customize what you want:
Child blade
#extends('master')
#section('css')
#parent
<!-- more css -->
#endsection
#section('navbar')
#parent
#endsection
#section('content')
<!-- Main content goes here -->
#endsection
#section('js')
<!-- replace js and add my own -->
<!-- others js -->
#endsection
Did you try extending your child blade file to use the master template?
At the top of layouts.frontend.partials.slider did you put #extends('layout.master') (or whatever the path to your master template is?)
It could be an issue caused by the order in which you are including files. Wouldn't a simpler solution be to have a #yield('slider') in your master template and simply wrap the slider content in #section('slider') and drop the #include...?

Resources