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.
Related
This question already has answers here:
Is it possible to make Razor sections optional?
(5 answers)
Closed 8 years ago.
I have an ASP.NET MVC layout page that is used by all the views in my application. Each of these views defines a "PanelRight" section, that is rendered in the layout page. However, now I would like to replace that section with some other markup. I thought it'd be as easy as commenting out the RenderSection instruction and adding my new markup, but I keep getting an exception ("The following sections have been defined but have not been rendered for the layout page").
I understand what the exception means; I only want to know how to get rid of it. Id est, can I NOT render a certain section that is defined in the views? Because I'd much rather not go through all of them and removing the section.
EDIT
I'll try to be more clear.
Suppose this is my layout page:
<html>
<head> <!-- HEAD STUFF --> </head>
<body>
#RenderSection("RightPanel", false)
#RenderBody()
</body>
</html>
and this is one of my many views:
#section RightPanel {
<div>This is the markup of the section</div>
}
<div>This is the body of my view</div>
Now I decide that, rather than having a RightPanel section that can be customized by each view, I want to have a fixed content instead. So I "remove" the section and replace it with the markup I want to use - straight into the layout (actually it will be in another partial, but not in a section, that's the point).
Of course, I don't want to go through all of my many views to delete the #section RightPanel { }. I just want the layout page to ignore the section. To make a comparison, it's like I defined a class with a DoFancyStuff() method, and then in the client code I never call that method. Not a problem there, so I see no reason why it would be here.
To recap: the view defines a section, the layout doesn't intend to render it. This results in an error. Is there a way to do this?
No, you cannot have a section in your view that your layout does not implement. This will result in a runtime error, and there's no way around that. The reason everyone is telling you how to implement optional sections is because the layout must implement any section any view might want to use, but, by making it optional, you can allow some views to use some sections while other views use other sections.
So, if I want to "comment out" a RenderSection, if just for a test, do I really have to go through all views and remove that section definition?
Technically, yes. Although you could simply wrap the section in regular HTML comments <!-- -->, so while it's rendered, it's rendered as an HTML comment instead of actual DOM elements. Also, with layout inheritance, you can sort of short circuit the views' sections by defining an empty section. For example:
_Layout.cshtml
#RenderSection("Foo")
_SubLayout.cshtml
#{ Layout = "~/Views/Shared/_Layout.cshtml"; }
#section Foo {}
SomeView.cshtml
#{ Layout = "~/Views/Shared/_SubLayout.cshtml"; }
#section Foo
{
<!-- stuff here -->
}
The section Foo would be empty because the sub-layout implements Foo but doesn't also call #RenderSection("Foo") itself, so there's no opportunity for a view using it as a layout to alter that section. That won't really help you now much, but it's good to know for future reference.
I suppose you could create a new layout with a different name and move the stuff from your current layout there while making your current layout inherit from the new layout. That would allow you to implement this without having to update all your layout references in your views. However, it will likely be easier to just to use HTML comments to comment out your section in your layout for testing purposes.
UPDATE
Just one more thing. Now that I'm thinking about it, the layout inheritance approach I suggested as one potential method, may actually not work. It occurred to me that you may still get an error because the sub-layout doesn't call #RenderSection. It all depends on whether the initial call in the main layout is enough to satisfy. HTML comments are definitely the safest and easiest approach.
UPDATE BY OP
Accepted answer:
you could simply wrap the section in regular HTML comments <!-- -->, so while it's rendered, it's rendered as an HTML comment instead of actual DOM elements.
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.
So my question is, hopefully, very simple.
I have two different domains with corresponding controllers/view folders etc.
I want to call the second _form.gsp from the first _form.gsp (within a g:each as there will be multiple things to display) and pass in the relevant data for the second _form.gsp to render from, how do I do that?
I know I can use g:render template = "myotherForm" but I don't know how to point it to another view folder or how to pass in the details...
Thanks in advance and let me know if more information is required...
You can Refer this
Grails uses the convention of placing underscore before the name of a view to identify it as a template.
Example grails-app/views/book/_bookTemplate.gsp:
<div class="book" id="${book?.id}">
<div>Title: ${book?.title}</div>
<div>Author: ${book?.author?.name}</div>
</div>
Then use render tag
<g:render template="bookTemplate" model="[book: myBook]" />
You're right, <g:render is the right tool. By default, for template="myOtherTempalte" it looks for tempalte in current directory, but you could pass full path, if it's from another controller. Like template="/forms/myOtherTemplate". And use model="" to pass parameters, same as inside controller:
<g:each in="${things}" var="x">
<g:render template="/forms/myOtherTemplate" model="${thing: x}"/>
</g:each>
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
I'm just getting started with grails, and I'm having an issue.
I have a "controller" and "view" for the projects home page (there's no model for the home page)
I called the view "index.gsp", and put it in a directory views/home
However, no matter what I do, grails is trying to read the page "home.gsp" (and then home.jsp), despite me having explicitly specified the index with the "template" attribute in the render call.
class HomeController {
String someparameter = "xyzzy"
def index = {
render(view:"home", template:"index") // I also tried "index.gsp" and "home/index.gsp"
}
}
I think I may be using the "template" attribute wrong, because I only see it used in examples for view-less template rendering. However the documentation gives no such limitation.
Is there any way to explicitly specify the name of a template? I just caved in and renamed it "home.gsp", but I'd like to understand what's going wrong.
(The home page in this application has no "model". Grails will use the controller has the model. In this example, you can access "someparameter" in the gsp template as ${someparameter}.)
I think you may be misunderstanding what a Grails template is. Think of a template as a reusable fragment. A template is a GSP that starts with an underscore like _menu.gsp that you would typically render from within another GSP with the a tag like <g:render template="menu"/>.
It doesn't make sense to render both a view and a template at the same time. They are mutually exclusive at this point.
Are you looking to implement a Layout? If so, see the docs or the grails.org explaination.
Basically, your view you would have a <meta name="layout" content="main"> tag in the <head/> tag of your view -- which indicates that the view will be meshed together with the main layout located in grails-app/views/layouts/main.gsp