Is it possible to pass parameters to layout in thymeleaf layout-dialect? - thymeleaf

I have a common layout which, by default, should display a (basic) search form on each page excepted the search page itself which contains a (more advanced) search form already.
Is it possible to pass a parameter from my search page to the layout in order to not display the default search form?
Here is an example of what I would like to do:
layout.html
<html layout:???="displayShowForm = true">
...
<form action="search" th:if="${displayShowForm}">...</form>
...
<div layout:fragment="content">...</div>
home.html (show the default search form)
<html layout:decorator="layout">
...
<div layout:fragment="content">...</div>
search.html (hide the default search form)
<html layout:decorator="layout (displayShowForm = false)">
...
<div layout:fragment="content">
...
<form action="advancedSearch">...</form>

Yes, it's entirely possible, even though Thymeleaf's documentation doesn't clearly state it.
All you have to do is pass your param using the th:with attribute. There may be other methods, but this seems to be the most straight-forward.
Here's a stripped down version of my implementation:
Default decorator - fragments/layout/default.html
<!doctype html>
<html xmlns:layout="http://www.thymeleaf.org" xmlns:th="http://www.thymeleaf.org">
<body>
<div th:replace="fragments/header :: main"></div>
<div layout:fragment="content">
main content goes here
</div>
</body>
</html>
Header fragment - fragments/header.html
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<div th:fragment="main">
<nav>
<ul>
<li>Home Page</li>
<li>About</li>
</ul>
</nav>
</div>
</body>
Home Page file - home.html
<!doctype html>
<html layout:decorator="layout/default" th:with="currentPage='home'"
xmlns:layout="http://www.thymeleaf.org/" xmlns:th="http://www.thymeleaf.org">
<body>
<div layout:fragment="content">
This is my home page content... thrilling, isn't it?
</div>
</body>
</html>
Here, in the home.html file, you can see I include the default decorator and pass my parameter using the th:with attribute. I don't actually use my parameter in my layout decorator, but I use it in header.html, which is included from the decorator. No need to pass it from the decorator to the header.html fragment, since it's already in scope.
There was also no need to do a NULL check on the currentPage variable in header.html. The active CSS class was simply not appended when removing the parameter from home.html.
If I were to render home.html, I would expect to see the following output:
<!doctype html>
<html>
<body>
<nav>
<ul>
<li>Home Page</li>
<li>About</li>
</ul>
</nav>
<div>
This is my home page content... thrilling, isn't it?
</div>
</body>
</html>

Yes, it is possible to pass parameters but you need to use layout:include instead of layout:decorator or layout:fragment.
Similar to Thymeleaf's th:include, but allows the passing of entire
element fragments to the included page. Useful if you have some HTML
that you want to reuse, but whose contents are too complex to
determine or construct with context variables alone.
Source : https://github.com/ultraq/thymeleaf-layout-dialect
You should take a look at this documentation which will give you details about the way to use it.
In your case, it could look like :
<div layout:include="form" th:with="displayShowForm=true"></div>
And in the layout page of form :
<div layout:fragment="form">
<div th:if="${displayShowForm} == true">
<form action="basicSearch"></form>
</div>
<div th:if="${displayShowForm} == false">
<form action="advancedSearch"></form>
</div>
</div>

Related

Apitome sidebar disappears when included in a layout

I am using the rspec_api_documentation and apitome gems in a version 5.2 ruby on rails app.
This produces excellent documentation, and has a sidebar (div#sidebar) to allow quick access to the correct part of the documentation. When I choose the
config.layout = "layouts/application.html.erb"
option in the apitome.rb initializer, the documentation is rendered, but the sidebar has disappeared. Looking at the page source, the code for the sidebar is not being rendered, i.e. it is not a css problem, the html is not being put into the layout. To make sure it was not something unusual in my application.html.erb file, I simplified it to this
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<%= yield %>
</body>
</html>
This sidebar is very useful, so how do I render it in a layout?
Based on the response to this issue, I was able to solve this.
I created a new layout at app/views/layouts.apidocs.html.erb which rendered apitome/docs/navigation. A simple example would be as follows
# app/views/layouts/apidocs.html.erb
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-4">
<div id="sidebar" class="sidebar hidden-print" role="complementary">
<%= render 'apitome/docs/navigation' %>
</div>
</div>
<div class="col-md-8" role="main">
<div class="docs-section">
<%= yield %>
</div>
</div>
</div>
</div>
</body>
</html>
I then configured this layout in the
apitome initialiser.
# config/initializers/apitome
Apitome.setup do |config|
...
config.layout = "layouts/apidocs.html.erb"
end
After some css tinkering, it all looked good.

How to get form data in Java Spark using Thymeleaf template engine?

I've built a simple application and now I'm trying to host attach it to a web server. I'm attempting to have a HTML form (using Thymeleaf) that the user enters their location in as text, and then my server will take and produce a result using that string. So to get started, I'm attempting to make a simple spark application that makes a home page with a "enter your location" form, that then gets the users input and does something with it. I can get the "entryMessage" displayed, as tutorials show, but how to get user data is proving difficult.
However, there is very little documentation on how this can be done with these two framworks. My attempt at what the code should look like is as follows. Note the middle post is just me trying to find ways to get the form data - none proved succesful
ThymeleafTemplateEngine engine = new ThymeleafTemplateEngine();
HashMap<String, String> userLocationMap = new HashMap<>();
get("/home", (request, response) -> {
userLocationMap.put("entryMessage", "Please enter your location");
return new ModelAndView(userLocationMap, "home");
}, engine);
post("/home", (request, response) -> {
System.out.println(request.toString());
//System.out.println(request.body());
//System.out.println(userResponse.location);
//response.redirect("/locationAccepted");
return userLocationMap.get("userLocation");
});
get("/locationAccepted", (request, response) -> {
String location = request.queryParams("userLocation");
return new ModelAndView(userLocationMap, "locationAccepted");
}, engine);
with the following thymeleaf templates
home.html
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p> <span th:text="${entryMessage}"> default message </span> </p>
<form action="/locationAccepted" method="post">
<input type="text" th:field="userLocation"/>
<div class="button">
<button type="submit">Send your message</button>
</div>
</form>
</body>
</html>
and locationAccepted.html
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p> <span th:text="${userLocation}"> default message </span> </p>
</form>
</body>
</html>
You have two bugs in your code, both in the HTML form:
In your Java code you're defining the route "/locationAccepted" as GET, but your form method attribute is POST => Change your form to GET.
If you want to get the form's input data it should have a name with value userLocation. th:field isn't translated to name (it's translated to field attribute which I'm not sure what it means).
So your form (after Thymeleaf) should look like this:
<form action="/locationAccepted" method="GET">
<input type="text" name="userLocation"/>
<div class="button">
<button type="submit">Send your message</button>
</div>
</form>
And then request.queryParams("userLocation") will work like you wanted.

Jquery Mobile : Is it possible to Open data-role="page" as Popup?

I want to open a new page as popup. I google it but not able to find answer.
Is Possible to do like that ??
Any Other Method to like that..I search all the Jquery mobile Doc. but not able to find any thing.
Here is my Code::
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Jquery Popup</title>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.2/jquery.mobile-1.3.2.min.css">
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.jquery.com/mobile/1.3.2/jquery.mobile-1.3.2.min.js"></script>
</head>
<body>
<div data-role="page">
<h1> Jquery Open Page in PopUp Examples</h1>
Open Page in PopUp
</div>
<div data-role="page">
<div data-role="Header">
<p>
PopUp
</p>
</div>
<div data-role="content">
<h2>
Content Page ??
</h2>
<p>
This is a regular page, styled as a dialog. To create a dialog, just link to a normal page and include a transition and data-rel="dialog" attribute.
</p>
</div>
<div data-role="Footer">
Sounds Good
Cancel
</div>
</div>
</body>
</html>
Short answer is no, it cant be done, at least in jQuery Mobile versions < 1.4. Popup as it is MUST be part of the page DIV and as such it can't be accessed outside of a page.
There is another solution, you can replace your second page div with data-role="popup" and place it inside a first page DIV, it would look like this:
jsFiddle example: http://jsfiddle.net/Gajotres/PMrDn/103/
HTML :
<div data-role="page">
<h1> Jquery Open Page in PopUp Examples</h1>
Open Page in PopUp
<div data-role="popup" id="popupExample">
<div data-role="header"class="ui-content">
<p>
PopUp
</p>
</div>
<div data-role="content">
<h2>
Content Page ??
</h2>
<p>
This is a regular page, styled as a dialog. To create a dialog, just link to a normal page and include a transition and data-rel="dialog" attribute.
</p>
</div>
<div data-role="footer" class="ui-content">
Sounds Good
Cancel
</div>
</div>
</div>
You will need to play with a CSS to make it look nicer.
Other solution would be to wait for jQuery Mobile 1.4 which will allow for popup to be placed outside page DIV, so you can share it among several pages. Unfortunately jQuery Mobile is in alpha state and this feature is still not working correctly.

JQM : Div with data-role page will sit on top of other element

I've developed an app for ios and android using phonegap. It's a dictionary app and it will display result in multiple tab (the tab is a div, every div will display different content). I use my own code so that only one div is shown at any time. Now I want to include jquerymobile so that I can apply a animation/transition when switching to other div.
So I add the data-role="page" to each div, which I assume will work immediately(like sample code below). But something is not right.
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.css" />
<script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"></script>
</head>
<body>
<table id="headergroup">
<tr><td>
<input>.........
<img>.......
</table>
<wrapper>
<div data-role="page" id="tab1">
<div data-role="header">
<h1>Page Title</h1>
</div>
<div data-role="content">
<p>Page1 content goes here.</p>
</div>
<div data-role="footer">
<h4>Page Footer</h4>
</div>
</div>
.........other div......
<div data-role="page" id="tabN">
<div data-role="header">
<h1>Page Title</h1>
</div>
<div data-role="content">
<p>PageN content goes here.</p>
</div>
<div data-role="footer">
<h4>Page Footer</h4>
</div>
</div>
</wrapper>
<div id="footer>
<img .......>
</div>
</body>
</html>
Supposely, my app should display the div(s) in the wrapper only. But the problem is, now my app will display the div with data-role=page in full screen and on top of other element (my app header and footer were not shown).
Is my implementation correct? How do I overcome this problem? Thanks.
You may get by with this on the first page, but on all other pages you are loading in via JQM-Ajax (default), you will only grab what's inside your first(!) div-data-role="page" from the page you are loading. Everything else (table, 2nd, 3rd page-div will not be loaded, because it's outside the page-div.
Have a look at the JQM docs on page anatomy and linking pages.
JQM is based on page-divs, so also in your code the page-div will get most "JQM attention" being set to fullscreen size and of cource hovering above everything else.
To use JQM you will either go with
Single page layout = page by page
Multi pape layout = multiple pages contained in one document.
Since you are using Phonegap, which I think bundles everything into a single file eventually, you may be better off with multipage. There is also a subpage widget or multiview, if you need to load documents with multiple "nested pages" from your initial page.

jQuery Mobile layout in ASP.NET MVC app

Short:
Do you put the data-role portions (header|content|footer) in your layout/master page or in each view in ASP.NET MVC?
Long:
Trying to find the 'best practice' with handling jQuery mobile layout. The docs (and some others) show:
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
...
</head>
<body>
<div data-role="page">
<div data-role="header">...</div>
<div data-role="content">#RenderBody()</div>
<div data-role="footer">...</div>
</div>
</body>
</html>
However I have seen this too :
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
...
</head>
<body>
<div data-role="page">
#RenderBody()
</div>
</body>
</html>
With each view having:
<div data-role="page">
<div data-role="header">...</div>
<div data-role="content">...</div>
<div data-role="footer">...</div>
</div>
So, do you define the header|content|footer in each 'view' in ASP.NET or in the layout/master? Is one better? Does it matter at all?
I've noticed that navigation (using the back button) only works correctly when you use the first option (DRY). I am facing the same issue. If I want different header content how do you change this if you have one layout page. I think the way to go is to create sections in the master layout page and enable them per view as required.
RenderSection("SectionName")
Personally, I've been using the second practice for Don't-Repeat-Yourself sake.

Resources