Grails relative path to controllers view folder - grails

Having a Grails 2.1 application, where I have a taglibrary for rendering a summary for different controllers, I have an issue pointing at the correct view-folder.
Eg. TestAController and TestBController both have a controller specific view file called summary.gsp in their respective view folders. That is /testa/summary.gsp and /testb/summary.gsp.
How can I my taglib render the summary.gsp that is related to the controller currently in action - I need to set a path like "??/summary-gsp".
I don't want to implement any if/else logic as there could potentially be 10000 controllers using this taglib, all specifying their own summary.gsp.
Is this doable?

You can access the params object in your taglib so:
out << render(template: "/${params.controller}/summary")

The caller should pass in the path to the template as an argument to the tag. If this argument is omitted you could use a convention for locating the template, e.g.
class MyTagLib {
def renderSummary = {attrs ->
def defaultTemplatePath = "/${params.controller}/summary"
def templatePath = attrs.template ?: defaultTemplatePath
out << g.render(template: templatePath)
}
}

Related

How to pass a list to view/layouts pages in grails

I know how to pass parameter from controller to view. But I have a common view template common.gsp. Which is in views/layouts folder. I want to pass a list to common.gsp.
How can I do that without passing parameter from all action.
You can use.
def ListOfObject=[]
render template: '/layouts/common', model: [desiredList: ListOfObject]

Can't access domain class methods in loaded template

I'm using Grails 1.3.8 (old but gold). In my view I render a template with the same variables as of the containing view via:
<g:render template="areaInfoTemplate" model="${pageScope.variables}"/>
This works unless I try to access methods on domain classes inside the template:
<g:if test="${currentState == State.findByName('foobar')}">...</g:if>
Leads to:
Exception Message: Cannot invoke method findByName() on null object
If I access State in the main view gsp everything is ok.
My domain class is:
class State {
String name
String value
static constraints = {
name(nullable:false,blank:false,size:0..255)
value(nullable:false,blank:false,size:0..255)
}
}
Grails isn't PHP - please don't make database calls from the view layer (unless you like to fight artificial, self-inflicted scalability issues). Just make the calls in a controller or service and pass the data to the view to be rendered. GSPs should only be responsible for rendering output, not higher-level concerns like database access.
I forgot to add an import statement at the beginning of the file:
<%# page import="my.wonderful.package.State"%>

Can I use a Bean as a model in grails instead of a Map?

Short Question: I'd like to use a typed bean as a model in grails instead of a Map. Is this possible?
I'd like to do this:
def index = {
new Person(firstName:"foo", lastName:"bar", age:30)
}
Instead of this:
def index = {
[firstName:"foo", lastName:"bar", age:30]
}
Long Question: I'm maintinaing a controller written by other developers and it's really difficult to understand all of the possible entries in the model. The model is populated over a number of methods. I'd like to refactor the controller to return a custom bean as the model but I was hoping that the gsp would not need to be changed.
I assumed that grails could handle either a map or a bean as a model but soon realised that passing a bean to the gsp resulted in NullPointerExceptions as properties could not be found.
I realise that my controller can return a map like:
[model: myBean]
But then I would need to go through the gsp and change all references from ${someProp} to ${model.someProp}.
I'm also aware that I can use reflection to convert my bean to a Map but I'd prefer not to do this either.
See render doc reference. You can find in examples
// render a template to the response for the specified bean
def theShining = new Book(title: 'The Shining', author: 'Stephen King')
render(template: "book", bean: theShining)
At the end of your controller: (Note this will return all properties)
New Person().properties

Grails: How do I map a URL to a controller inside a custom plugin?

I have a controller inside a plugin called TextController with an action called index
I then have a view inside the calling application called test-plugin.gsp with the following include tag:
<g:include controller="text" />
This works great. The problem is that the plugin's controller actually needs to identified by a package-like name, such as: com.foxbomb.fxportal3.components.text, and I need to reference it as such. So my thinking us to try and have a URL mapping for the plugin, such as:
"/components/com.foxbomb.fxportal3.components.text/" {
controller = "text"
action = "index"
}
I also don't know how to create an include in the calling application to try and call that URL, something like (I know you don't get a URL attribute):
<g:include url="/components/com.foxbomb.fxportal3.components.text"/>
In other words, I want to include a controller / action by its mapping as opposed to its controller / action name.
<g:include> doesn't allow a url attribute, which surprises me, but looking at the source of the <g:include> tag it should be possible to implement this in your own taglib fairly easily (untested):
import org.codehaus.groovy.grails.web.util.WebUtils
class IncludeTagLib {
def grailsUrlMappingsHolder
def includeUri = { attrs, body ->
def mapping = grailsUrlMappingsHolder.match(attrs.uri)
out << WebUtils.includeForUrlMappingInfo(request, response, mapping,
attrs.model ?: [:])?.content
}
}
You'd say <g:includeUri uri="/components/com.foxbomb.fxportal3.components.text"/> in your GSP.

How to call a Grails service in a view?

Simple question :
I have a service class (let's say helpersService) and a method def constructURI(params).
How can I call this method from a template view.
I have tried the following code without success
<% def helpersService = new HelpersService() // or def helpersService
%>
<img src="${helpersService. constructURI(params)}"/>
But I get the following result:
No signature of method: com.HelpersService. constructURI() is applicable for argument types...
or (in case I use def helpersService)
Cannot invoke method constructURI() on null object
Any ideas?
Services are not intended to be used inside views. You could create a TagLib where you can get a reference to the service via dependency injection.
An easier method, assuming your view is being rendered by a Controller, is to just pass a reference to the service from the action to the view within the model, i.e.:
class someController {
def someService
def someAction = {
render(view: 'someView', model: ['someService': someService])
}
}
It can then be used as you would expect within the view. For a template rendered by a view, obviously you need to pass the reference to the template as well. Just to be clear though, S. Puchbauer is right; services are not really supposed to be used within Views, and you may experience difficult to diagnose problems, especially related to transactions and the Hibernate session.
I found out, that this groovy inline code works:
<% def xxxService = application.getAttribute("org.codehaus.groovy.grails.APPLICATION_CONTEXT").getBean("xxxService") %>
You can call functions of the service just like this:
<g:select optionKey="key" from="${xxxService.getWhateverList()}" name="tarif" value="${accountInstance?.tarif}" ></g:select>
Well I have found a workaround with the following code :
def helpersService = grailsApplication.classLoader.loadClass('HelpersService').newInstance()
However it is better to use Service via dependency injection, so I will try out Siegfried advice.
You can do this easily without creating a tag lib by using the set tag:
<g:set var="versionService" bean="versionService"/>
...
<p>version ${versionService.clientVersion}</p>
I found this solution here: http://mrhaki.blogspot.com/2013/08/grails-goodness-use-services-in-gsp.html

Resources