My Spring Boot app cannot see the Thymeleaf templates - spring

I have a Spring Boot app, where i define my thymeleaf dependency in pom.xml with these lines:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
So when i start the application and print the predefined bean names, i see these beans (which i think are important for thymeleaf to run properly):
templateEngine
thymeleafResourceResolver
thymeleafViewResolver
The project structure looks like this:
I have defined some fragments inside the fragments.html:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<body>
<div class="container" th:fragment="copy">
<hr>
<footer>
<div class="row">
<div class="col-lg-12">
<p>Copyright © Teamtool 2015</p>
</div>
</div>
</footer>
</div>
</body>
</html>
.. and i am trying to use those from my index.html like this:
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Hello AngularJS</title>
<base href="/" />
<link href="css/angular-bootstrap.css" rel="stylesheet">
<style type="text/css">
[ng\:cloak], [ng-cloak], .ng-cloak {
display: none !important;
}
</style>
</head>
<body ng-app="hello" ng-cloak class="ng-cloak">
<div ng-controller="navigation" class="container">
<ul class="nav nav-pills" role="tablist">
<li ng-class="{active:tab('home')}">home</li>
...
</ul>
</div>
<div ng-view class="container"></div>
<div class="col-md-3" th:include="fragments :: copy"></div>
<script src="js/angular-bootstrap.js" type="text/javascript"></script>
...
</body>
</html>
But my template is not added in the index.html. What do i do wrong?

Application scans Thymeleaf templates in templates folder, move index.html to templates that should work.

I try to be generic here, Spring boot considers static folder as public resources folder that it uses to serve static files from. As you are telling spring boot to also configure a templating system - thymeleaf in your case - it will start looking in templates folder. Thymeleaf templating is not static but a dynamic page building mechanism.
Now because you configured thymeleaf Springboot expects that you want to render dynamic thymeleaf template and its looking for a starting point from within templates folder. It does not find index.html file showing you a Whitelabel page. When you move index.html to template folder it has a default starting point. You can map any other file name as stating point to your application by mapping a URL path like #RequestMapping(value = "/") in one of you controller.
You can use static folder to serve angular JS files, but a template has to be in templates folder, unless you override it.

Related

Thymeleaf switch statement including every case

I'm working on my first Spring MVC project and I got stuck at a problem. I have 3 types of users in my application: admin, employee and customer. Depending on the type of user, I would like to have a specific type of menu for each of them. I tried using a switch statement in my thymeleaf template but every case gets included in the output and I don't understand why.
This is the code for my method in the controller:
#RequestMapping(value = "list/{roleId}", method = RequestMethod.GET)
public String listFood(Model model, #PathVariable int roleId){
model.addAttribute("title", "Available Foods");
model.addAttribute("roleId", roleId);
model.addAttribute("foods", foodDao.findAll());
return "food/list";
}
And this is the code from the Thymeleaf template (each fragment will be included in the resulting page):
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org/">
<head th:replace="fragments :: head"></head>
<body class="container">
<h1 th:text="${title}">Food</h1>
<div th:switch="${roleId}">
<p th:case="0"><nav th:replace="admin-fragments :: navigation"></nav></p>
<p th:case="1"><nav th:replace="employee-fragments :: navigation"></nav></p>
<p th:case="2"><nav th:replace="customer-fragments :: navigation"></nav></p>
</div>
</body>
</html>
However, if I change the template to the following one then only the correct case will be included in the resulting page.
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org/">
<head th:replace="fragments :: head"></head>
<body class="container">
<h1 th:text="${title}">Food</h1>
<div th:switch="${roleId}">
<p th:case="0">User is an administrator</p>
<p th:case="1">User is an employee</p>
<p th:case="2">User is a customer</p>
</div>
</body>
</html>
Why isn't the switch from the first template behaving like the one in the second template? What should I change in the first template to be able to have a personalised menu for each type of user? Thank you!

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!

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...?

Load specific js for certain pages in laravel

I am using laravel 4 for a project. Is there any way I can specify what js files I want to load for a certain view. Right now I am lumping all in one file.
When I use codeigniter, to load specific js files, i use a library to generate the script tags and echo them at the footer. something as below
$this->data['js'] = $this->js_lib->generate('jquery');
Then in my view
<?= $js ?>
Any idea how to do this in laravel?
Main Layout
main.blade.php
#include('includes.header')
<body>
<!-- main content -->
<div id="main_wrapper">
<div class="page_content">
#yield('content')
</div>
</div>
#include('includes.footer')
</body>
header.blade.php
<head>
<meta charset="UTF-8">
<title>My Page</title>
<meta name="viewport" content="initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<!-- common styles -->
<link rel="stylesheet" href="{{ asset('assets/bootstrap.css') }}">
<!-- page specific styles -->
#yield('pagespecificstyles')
</head>
footer.blade.php
<footer>
<!-- common scripts -->
<script src="{{ asset('assets/js/jquery.min.js') }}"></script>
<!-- page specific scripts -->
#yield('pagespecificscripts')
mypage.blade.php
#extends('layouts.main')
#section('pagespecificstyles')
<!-- flot charts css-->
<link rel="stylesheet" href="{{ asset('assets/lib/owl-carousel/flot.css') }}">
#stop
#section('content')
<div class="container">
Hello welcome to my page.
</div>
#endsection
#section('pagespecificscripts')
<!-- flot charts scripts-->
<script src="{{ asset('/assets/lib/flot/jquery.flot.min.js') }}"></script>
#stop
Stacks
Blade allows you to push to named stacks which can be rendered somewhere else in another view or layout. This can be particularly useful for specifying any JavaScript libraries required by your child views:
#push('scripts')
<script src="/example.js"></script>
#endpush
You may push to a stack as many times as needed. To render the complete stack contents, pass the name of the stack to the #stack directive:
<!-- Component Contents -->
#stack('scripts')
</body>
https://laravel.com/docs/5.7/blade#stacks
I know asked a while ago but for the benefit of others who may stumble here! One option is also in your layout to define additional sections, e.g.
#yield('css') <!-- In the head -->
#yield('js') <!-- Before the </body> tag -->
Then in your views
#extends('some.layout')
#section('css')
#include('js/dependencies/some/js/dependency/css.css')
#append
<!-- So in case these dependencies are used elsewhere you're not repeating your script or link tags over and over -->
#section('js')
#include('js/dependencies/some/js/dependency/js.js')
#include('js/dependencies/some/js/dependency/js2.js')
#append
#section('content')
Your actual content
#endsection
Just have a 'partials' view folder - and include whatever script you want in each view.
So in your view;
<body>
// Your main content here
// Other JS files you want in all views
#include('partials.analytics.blade.php')
#include('partials.googlemaps')
#include('partials.some_other_js_file')
</body>
Then have /views/partials/analytics.blade.php
<script>
// Your JS analytics script here
</script>
and just repeat for each 'script'
You may add the following code in your app.blade file
#stack('scripts')
and then you can use the jquery on page
#push('scripts')
<script type="text/javascript">
///Js code
</script>
#endpush

Extend A View With Thymeleaf

is it possible extend a shared view with thymeleaf?
I saw that is possible use framents but is not what I want.
Instead I want something similar to .NET MVC, with something like #RenderBody() and another view that extend the shared view by including the shared view.
You can use the Thymeleaf Layout Dialect to extend a view.
Layout page
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
...
<body layout:fragment="body">
...
</body>
</html>
Content page
In your content page, you refer to the layout (decorator) page using the layout:decorator attribute.
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorator="layout.html">
...
<body layout:fragment="body">
<p>Actual page content</p>
</body>
</html>
It is possible to have multiple fragments in one page.
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
...
<body>
<div layout:fragment="content"></div>
<footer layout:fragment="footer"></footer>
</body>
</html>

Resources