conditional check in grails site mesh - grails

I have my gsp pages all applying the layout from main.gsp. Main.gsp is using the bootstrap layout and a container to make the pages responsive. In a few of the pages on my site I'm trying to use a liquid layout and don't want to have a container wrapping all of the content in each of the sub pages.
Is there a way to pass a variable or set something in a page that applies the layout of main.gsp, and have a conditional piece of code execute in the main layout?
Neither of these attempts below worked. In one I'm setting a variable in the sub page, and in another attempt I'm passing in a variable in the model. In both cases the container is being rendered in profile.gsp.
main.gsp:
<body>
<g:if test="${fluid != true}">
<div class="container">
</g:if>
...
profile.gsp:
<g:set var="fluid" value="true"/>
<g:applyLayout name="main" model="[fluid:'true']">
<html>
<head>
...

You are Setting a String value to var fluid in:
<g:set var="fluid" value="true"/>
In case <g:if test="${fluid != true}"> it is checking a boolean not string comparison so you need to define either a boolean or you need to check for sstring comparison.
To set boolean you can do <g:set var="fluid" value="${true}"/> cause "true" will make it just a string with value true not a boolean true.

in addtion to Sachin Vermas response, you can use two additional approaches:
not a clean solution, but it should work: in the layout, there is the params-map and the session available, so you could store your flag in one of those objects.
another solution would be to not only do a conditional check in your layout, but use a whole new layout:
'<g:applyLayout name="${fluid?'fluid':'main'" >'
but as Sachin Verma already replyed, the fluid variable has to be of the right type. As I do understand, in your case you even wouldn't have to dynamicalle switch between two layouts, but you could just use `
<g:applyLayout name="fluid" >`
for your fluid pages and `
<g:applyLayout name="main" >`
otherwise. This would make your code even cleaner in case that you not only have to hide a div.

Related

Set variable in layout and access it in template

I'm setting a variable in grails-app/views/layout/main.gsp to a value, like
<g:set var="welcometext" scope="session">Hello, pleased to meet you!</g:set>
But when I try to access it in my view grails/app/views/index.gsp with
<html>
<head>
<meta name="layout" content="main"/>
</head>
${welcometext}
<body>
</html>
Nothing gets printed out. So the variable set in main.gsp is not accessible to my view index.gsp. I tried also to set the scope to page, request and session, but success.
How can I set a variable in my layout main.gsp and reference it in other views?
You can define variables in your page (index) and your layout can see them (which is really useful for breadcrumb for example).
However, you can't access to a variable defined in your layout from your page (index) because the page is rendered like there was no layout, and then we apply the layout to the page rendered.
As a shortcut, you can see the rendering flow like this: (render Index) THEN (render Layout)
So, in your case, you have to find another solution, depending on your content:
Put the welcometext in session (not the best solution)
Pass it as a parameter of each view (not the best solution)
Create a custom tag to automatically print it
Create a template and render it where you need
Hardcode it ? (I don't like this one, but it's closer to what you're trying to do)
Use JavaScript to add the text ?
...
Try to see which one is the best for you ;)

Dereferecing in gsp inner html

I have a layout file. I want something like this in each of my pages inheriting that layout:
Just ${step} Steps Away From The Awesome!!
So in my layout I have defined a string as above with a placeholder step. I dont want to pass the value of this placeholder from controller. I wish to define it in the gsp that inherits this layout.
I was looking for something like <g:set var="step" value="1"/> (or 2 or 3 depending on the gsp). But it does not work if I define it like that.So how do I dereference the value of "step" inside each extending layout?
One of the best ways to accomplish this is to make use of content blocks and page properties. These are both features derived from Sitemesh.
I assume you only want to conditionally include this information when the page using the layout provides a value. So in my example here I have wrapped it in a quick if check.
In your layout:
<g:if test="${pageProperty(name: 'page.step')}">
Just <g:pageProperty name="page.step" /> Steps Away From The Awesome!!
</g:if>
Then in any page that uses the layout you can include the content for the variable step
<content tag="step">3</content>
Note that the value within the content tag can be whatever you like. It will be evaluated when the page is rendered.

How to use fields in Comfortable Mexican Sofa?

I have seen in documentation that fields are not rendered in the view, and instead it can be used in helpers, partials etc. but I can't find a way how they are used.
The documentation says to use it like this:
{{ cms:field:some_label }}
But I am courios how can I use that? I wanted to be able to define some text in the snippet and then, use that field in my partial or in my helper function to form some data that will be used in the view. Can somebody tell me how can I use fields in this CMS?
Imagine you have a CMS site set up so it's using an application layout. Somewhere in that layout you have: <meta name="description" content="Something about the page"> Now, how do you dynamically populate content of that tag from the page? We can define {{cms:field:meta_description}} tag.
In the admin area you'll be able to populate it and. Now you need to output that like this:
<meta name="description" content="<%= cms_block_content(:meta_description) %>">

Override Grails <g:set> variable's value in a <g:layoutBody>

I have a layout.gsp where I define some markup for a control (say, banner) that might be displayed on any page (or might not).
<g:set var="showBanner" value="${...}" scope="page|request|flash|session"/>
<!-- Some more logic that may g:set showBanner var -->
<g:layoutBody/>
<g:if test="${[flash|request|???].showBanner}">
<div id="banner">...</div>
</g:if>
The idea is to let the page, rendered by <g:layoutBody>, to decide if it wants the banner on it or not. So, one page may decide to always show banner, as following - page1.gsp:
<g:set var="showBanner" value="${true}" scope="page|request|flash|session"/>
Another page decides to never show banner on it, as following - page2.gsp:
<g:set var="showBanner" value="${false}" scope="page|request|flash|session"/>
Unfortunately, this approach doesn't work for me. I tried all different combinations of scope attribute and still cannot have it overridden in children pages.
Is this a wrong approach in general or I miss some detail?
I found what I was doing wrong. The issue is that variables set inside included page are evaluated before the layout.gsp code runs, not at the moment of <g:layoutBody/> tag insertion (or call).
In other words, dependencies are rendered before the layout, not at the moment layout directive is encountered. This may be intuitive for some, but not for others (not for me).
Another point is that you still need to use request scope to access the same var between pages (which is quite intuitive).
So, the solution becomes:
First in page1.gsp:
<g:set var="showBanner" value="${true}" scope="request"/>
Then in layout.gsp:
<!-- Doesn't matter were you put it, always evaluated first -->
<g:layoutBody/>
<g:if test="request.showBanner == null"> <!-- if not set by children page -->
<g:set var="showBanner" value="${...}" scope="request"/>
<!-- Some more logic that may g:set request.showBanner var -->
</g:if>
<g:if test="${request.showBanner}">
<div id="banner">...</div>
</g:if>
What about you set the variable inside an interceptor? Like one shown here: Accessing the model from a layout view in Grails

What's the right way to handle action state in the layout page?

What I mean is this: I've got a layout page that shows a different favicon depending on what action is being invoked. So I've got some code in the layout that looks like this:
<link href="/images/favicon/#(AmbientPage.ShortName).ico" type="image/ico" rel="icon" />
The AmbientPage variable is a global value that's set in the Index action, and read by the layout file, which dynamically writes the icon filename for whatever page was requested. This seems really kludgy to me, but I'm not seeing a great way around it either.
What do you do when the Layout page needs to know something that happened in the action?
Usually I would use a child action or section to avoid having logics in the layout page. So in the case above, other ways of doing it would be passing the name of the current page to an child action and let child action determine what icon/action to use.
It would be something like:
#Html.Action("Icon", "Default", new { #ViewContext.RouteData["Action"] })
Or using an section, in layout page, you add the following code
//true since they all required to have an icon
#RenderSection("Icon", true)
then in your view you just do
#section Icon{
<link href="/images/favicon/currentpage.ico" type="image/ico" rel="icon" />
}
Personally, I would suggest you to use the section approach to make the code "less dependent" on each other

Resources