grails template is not searched in views main directory - grails

I have a template which I render with:
<g:render template="recordInfo" />
in my main-layout. (layout/main.gsp).
That's a template, which some of my views need and some views don't.
For the views, which don't need that template, I put an empty file with the name in the top-level-views directory (/grails-app/views). As described in the grails documentation:
Without the leading '/' it will be first be resolved relative to the
current controller's view directory then, failing that, the top level
views directory.
It works fine for the views which have the template-file in the own view-directory (e.g. /grails-app/views/address). But it doesn't work, where grails should search the template at the /grails-app/views level.
Do I understand something wrong from the documentation or do I have an error in my code?
My file/directory structure looks like:
...
MyApp/grails-app/views/_recordInfo.gsp
MyApp/grails-app/views/address/_form.gsp
MyApp/grails-app/views/address/ ...
MyApp/grails-app/views/address/_recordInfo.gsp
MyApp/grails-app/views/contact/_form.gsp
MyApp/grails-app/views/contact/ ...
...
The address-view needs a customized _recordInfo template and the contact-view don't need it (and therefore I thought grails would pick up the one in the MyApp/grails-app/views directory...)

Related

Applying a master page template in Sling with HTL

Is there any simple way to apply a page template to multiple Apache Sling scripts?
I'm looking for something akin to the JSP 2.0 Tag option. However, I'm using HTL, which doesn't support such tags.
I could, of course, use HTL includes, such as data-sly-include="${'header.html'}, but these would then have to be manually included in every page I then create.
Ideally I'd like to be able to have a master page containing the layout, which is then automatically applied to all pages of specified resource types, leaving a customisable area for content specific to each resource. I'd then be able to limit my add.html, edit.html, html.html (etc) files to include only a block of code for the content section of the page, preventing unnecessary duplication of layout code across multiple files.
I thought I might be able to achieve this by creating a master page resource (e.g. "page"), then setting sling:resourceSuperType on the individual resources but since this acts as a fallback, it'll only kick in if there's no matching script for the sling:resourceType - and there will be such scripts.
You could use a Sling Decorator to wrap your resources so that they always get handled by the common scripts before everything else. This way you can impose the template and include the actual resource to fill in the actual values/blocks/custom scripts.
Another option would be to impose a (nested) content tree where the root points to the template scripts (using JCR type, for example) while the children/content point to the custom scripts (using resource type). This is pretty much what AEM does with cq:Page and its jcr:content.
I ended up using the following approach:
Add a new resource type page
Create a Sightly/HTL template file for the page resource type (/apps/page/html.html); this is the 'master' page template
Include common elements in that template
Within that template, call the 'child' templates by adding the view selector through the following HTL element: <div data-sly-resource="${request.pathInfo # selectors='view', addSelectors=request.requestPathInfo.selectors, requestAttributes=request.requestParameterMap}">
For each sling:resourceType that's to be rendered as a page, add a view subfolder (/apps/example_type/view) and place its HTL templates within that folder (e.g. add.html, html.html)
On each resource that should be rendered with the master template, set sling:resourceSuperType to page
When a request comes in to, for example, /content/example_type_instance.add.html, Sling resolution will therefore try to find a script in /apps/example_type/add.html; there isn't one, so it falls back to the resourceSuperType script in apps/page/html.html, which in turn will use the script in /apps/example_type/view/add.html.
This seems to work for the moment. #Vlad's approach with a Sling ResourceDecorator may be more elegant.

Html.RenderPartial - Render Partial View located in another folder

I have my view 'Create.cshtml' in folder Views-Department. I want to use partial view which is located in folder on root, 'CommonViews' with the name '_EnterpriseStructure.cshtml'.
I am using syntax RenderPartial
#{Html.RenderPartial("~/CommonViews/_EnterpriseStructure.cshtml");}
Partial view code
<div id="Client">
This is a Partial View.
</div>
When executed I am getting System.InvalidOperationException.
Detail error is:
The view at '~/CommonViews/_EnterpriseStructure.cshtml' must derive from WebViewPage, or WebViewPage.
I am using ASP.Net MVC 5 Razor Views
I have found that Razor view engine is searching in folders 'Views/Shared', 'Views/Departments' . When I moved the Partial View, to folder 'Shared' it worked.
You cannot include path, you just have to give View name. And add folders to search for View engine.
What I cannot figure out is "How to give more Search locations to View Engine?"
I would reckon you to use T4MVC nuget package in your MVC project. Once the package is included in your project, you just need to select "T4MVC.tt" file in your project (solution explorer) and say "Run Custom Tool". That's it. This will create constants for almost everything in your MVC project. That means, all views, controllers, actions, javascript files, resources, css files, images, etc are now having constants.. This way you can avoid using the hard-coded strings for views etc in your methods, and can use constants generated by T4MVC. You won't need to worry about path of views etc. T4MVC is very effective and is must for MVC projects.

I need an explanation about how to use Grails (with different controllers)

I'm trying to create a little and basical Twitter-like site with Grails.
Here is the main part of my project arborescence (UserCwitter handles users, MessageCwitter handles messages and GroupCwitter handles groups like followers/followings) :
I'm trying to insert a text field to write a new message in the index (here it's index_final.gsp).
So I added this piece of code (in every controller my function to create a new user/message/groupe is called save()) :
<g:form action="save">
<fieldset class="form">
<g:render template="form"/>
</fieldset>
</g:form>
But I don't know why, the form that appears is the one to create a new user and not a message.
Why and what should I do ?
Thanks for your help. Sorry if this is something really easy or even stupid, I'm really new to Grails.
From render tag documentation, related to template attribute:
Note that if the value of the template attribute starts with a '/' it
will be resolved relative to the views directory. This is useful for
sharing templates between views. Without the leading '/' it will be
first be resolved relative to the current controller's view directory
then, failing that, the top level views directory.
So you should use
<g:render template="/messageCwitter/form"/>
if you want to render form template that is in messageCwitter folder.

How can I use an application layout in rails for all controllers except a few?

I have an application layout in my rails app to give a default header/footer for my entire website. I have 1 controller that I dont want this to apply to (a checkout page), and an entire namespace that needs to have a separate default template (the admin interface, which has 10-15 different controllers). What is the easiest way to do this?
app/views/layouts/application.html.erb
Will set the default for the entire layout. To override for a specific model, just have
app/views/layouts/mymodel.html.erb
I believe that will work for namespaces also, so long as your layouts directory structure matches your models' directory structure.
http://apidock.com/rails/ActionController/Layout/ClassMethods/layout
Just create new layout file (ie: /app/views/layouts/new_layout.html.erb) and set it in the beginning of the controller:
layout 'new_layout'

I can't get the grails controller "render" method to work with an explicit template

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

Resources