How to pass a specific object to a fragment (thymelaf) - spring

I have a problem that i would like to get help with!
I am using Intellij Idea and are using Spring MVC with Thymeleaf. I have created a fragment and all is fine and dandy, it works good and gets imported in my current html file.
<div th:replace="fragments/ModalCart :: modal(${products.get(0)})"></div>
This is my import statment and as you can see i am passing a single object of type Product.
This is my fragment html file
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
</head>
<body>
<div th:fragment="modal(product)">
<button id="myBtn">Open Modal</button>
<div id="myModal" class="modal">
<div class="modal-content">
<section class="card">
<div class="columns">
<div class="column">
<p th:text="${product.getImgUrl()}"></p>
</div>
</div>
</section>
</div>
</div>
</div>
</body>
</html>
My problem is that my 'product' in the modal fragment is of type Object not type Product as i would like to to be (because of that if i call the imgUrl getter method on the passed in product i get a red underline that tells me it can not be resolved, even doe it works i have a error in my html file which is annoying).
How would i make sure that the parameter that gets pass into this class is of type Product class and not of java.lang.Object class?
Is there any way to cast it back to a Product or am I stuck?
Thanks

Thymeleaf doesn't actually care about the type of the variable passed to the fragment, so ${product.getImgUrl()} (equivalent to ${product.imgUrl}) should work whether or not it has red underlines.
As for fixing those problems... this is IDE specific. For example, in Intellij I think something like this should work:
<div th:fragment="modal(product)">
<!--/*#thymesVar id="product" type="your.package.Product"*/-->
Where you replace your.package.Product with your actual package.

Related

Laravel 8.0, problems with #yield('content') make duplicity of the content section in other div

I have a newly started project in Laravel 8.0, and I have a problem with views.
I have the following master.blade.
<html>
<head>
<title>App Name - #yield('title')</title>
</head>
<body>
<div class="container">
#yield('content')
</div>
<footer class="row">
#include('layouts.footer')
</footer>
</body>
</html>
I then have a view that extends that master blade:
#extends('layouts.app')
#extends('layouts.master')
#section('content')
HELLO
#stop
The problem is, when rendering the view, the information is duplicated. Appears once inside the container div so the #yield works, but is re-rendered in another div outside the container (main class="py-4").
Let's see if someone can help me with the problem.
Thank you very much in advance.
#extends('layouts.master')
#section('content')
HELLO
#endsection
you extends two time
You must add one extends, edit the code and do the code below
#extends('layouts.master')
#section('content','your title')
HELLO
#endsection
that the right way to get the view.

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!

Thymleaf - how to call model Attribute on html document

Im trying to render a webapge and use the thymleaf attribute "url" added with model.addAttribute but the Attribute is not beeing displayed on the html document.
My document.html file path is here:
/templates/webpage/document.html
#RequestMapping(value = "/webpage/document")
public String document(HttpServletRequest req, Model model) {
model.addAttribute("dialogurl", url);
return "/webpage/document";
}
Here is the html document
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" th:include="wrapperdialog :: page">
<head>
<title></title>
</head>
<body>
<div th:fragment="content">
<div class="container dialogpage">
<div class="row">
<div class="col-md-12">
<div id="typeform" th:attr="data-url=*{dialogurl}">
</div>
</div>
</div>
</div>
</div>
Please use this expression to bind dialog url: #{${dialogurl}}
<div id="typeform" th:attr="data-url=#{${dialogurl}}">
# prefix is used to specify a link and $ prefix is used to bind your model value.
Use $ to bind data.
<div id="typeform" th:attr="data-url=${dialogurl}">

Laravel blade template yield in child

I've a master layout like this:
<head>
#yield('styles')
</head>
<body>
#include('header')
<div class="container-fluid">
#yield('content')
</div>
#yield('scripts')
</body>
Now I've following structure in page content:
#section('content')
<div class="page-content">
#include('sidebarandfooter')
</div>
#endsection
#section('copyright')
#include('copyrightv2')
#endsection
Sidebarandfooter.blade.php have following:
...[CODE for sidebar]...
#yield('copyright')
It's should be called inside <div class="container-fluid"></div> as I've different class of div container for different pages.
I'm not able to yield the copyright part. I've different copyright section for different pages. Is it wrong, how can we execute such kind?
Unfortunattely it's imposible in way you declare it because this section:
#section('copyright')
#include('copyrightv2')
#endsection
been loaded before you call this: #include('sidebarandfooter') with copyright section inside.
What you can do is to pass a key as a parameter to view to the included page content partial like this:
#section('content')
<div class="page-content">
#include('sidebarandfooter', ['copyrightsView' => 'copyrightv2'])
</div>
#endsection
and then just call inside Sidebarandfooter.blade.php in the include:
...[CODE for sidebar]...
#include($copyrightsView)
change your master layout like
<head>
#yield('styles')
</head>
<body>
#include('header')
<div class="container-fluid">
#yield('content')
</div>
#yield('copyright')
#yield('scripts')
</body>
since i am not seeing a section for copyright in your master layout

Thymeleaf + spring dynamic replace

Is it possible to create a dynamic replace in Thymeleaf?
I have the following controller:
#Controller
public class LoginController {
#RequestMapping("/login")
public String getLogin(Model model){
model.addAttribute("template","login");
return "index";
}
}
And the following view:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" >
<head></head>
<body>
<div th:replace="fragments/${template} :: ${template}"></div>
</body>
</html>
And i'm getting the following error:
Error resolving template "fragments/${template}", template might not exist or might not be accessible by any of the configured Template Resolvers
UPDATE
I tried to preprocess my variables like this:
<div th:replace="fragments/${__#{${template}}__} :: ${__#{${template}}__}"></div>
How ever now ${template} is getting replaced with login i have the following error now:
Exception evaluating SpringEL expression: "??login_en_US??"
Although Joe Essey's solution is working as well i solved with following code:
<div th:replace="#{'fragments/' + ${template}} :: ${template}"></div>
I believe the appropriate method to manage this behavior in thymeleaf is to use layout:fragment tags. Please correct me if I'm wrong. Here is a simple example of my layout page, and the login page which is 'dynamically' loaded:
layout.html
<html xmlns:layout="http://www.w3.org/1999/xhtml" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<title layout:title-pattern="$DECORATOR_TITLE - $CONTENT_TITLE">Layout</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=Edge"/>
</head>
<body>
<div>
<div class="app-container">
<div th:fragment="content">
</div>
</div>
</div>
<div th:fragment="script"></div>
</body>
</html>
Then, when login gets loaded, it replaces the th:fragment div with the associated div in the html view which matches the string returned by the controller method, in this case login.html:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.w3.org/1999/xhtml"
layout:decorator="layout">
<head>
<title>Login</title>
</head>
<body>
<div th:fragment="content">
<form th:action="#{/login}" method="post">
<div><label> User Name : <input type="text" name="username"/> </label></div>
<div><label> Password: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="Sign In"/></div>
</form>
</div>
</body>
</html>
Now, if you want to load another fragment conditionally, the approach I take is to add replace tags with th:if cases. Here's an example of a Form that displays different questions based on an attribute of the current user:
<div th:if="${foo.type)} == 'type_1'">
<div th:replace="fragments/custom-questions :: type-1-checkboxes"></div>
</div>
<div th:if="${foo.type} == 'type_2'">
<div th:replace="fragments/custom-questions :: type-2-checkboxes"></div>
</div>
Then the associated div gets loaded from the file custom-questions.html:
<div th:fragment="type-1-checkboxes">
//stuff
</div>
<div th:fragment="type-2-checkboxes">
//stuff
</div>
I am just encountering this issue (this is my first time with thymeleaf/spring). This is what solved it for me:
<div class="col-md-12" th:include="__${template}__ :: body" ...
In Thymeleaf 3.0, the following solution has worked for me:
<div th:replace="('fragments/' + ${template}) :: (${template})">
(Note however, that I use it with fixed name of the fragment and dynamic name of the template, so the parantheses around :: (${template}) might be optional.)
The solution is inspired by documentation for Thymeleaf in https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#fragment-specification-syntax
Both templatename and selector in the above examples can be fully-featured expressions (even conditionals!) like:
<div th:insert="footer :: (${user.isAdmin}? #{footer.admin} : #{footer.normaluser})"></div>
Note again how the surrounding ~{...} envelope is optional in th:insert/th:replace
<div th:insert=“${subpage}::fragementName”>
Just change subpage names and you will dynamic behaviour in thymleaf

Resources