How to call a Grails service in a view? - grails

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

Related

grails taglib get a list from controller

I came across a post from Donal which I think was asking he same thing but did not really anwer the question, a little puzzled and wonder if possible.
If I have a tag lib, user provides controller action I Wish for it to then go off query controller and return result as a list, I tried g.include with no luck. I have tried to expand on this below but don't know too much about it and if at all possible to actually get a value back from the given primaryAction or def value within controller
if (attrs.primaryController && attrs.primaryAction ) {
//def nlist= g.include(controller:'${attrs.primaryController}', action:'${attrs.primaryAction}', id:'${attrs?.primaryId}')
def controllerArtefact = grailsApplication?.getArtefactByLogicalPropertyName("Controller", "${attrs.primaryController}")
def controllerClass = controllerArtefact?.getClazz()
def aaa=controllerClass.declaredFields.each {
it.name=="${attrs.primaryAction}" }
println "-->"+aaa.getMetaPropertyValues().
println "-------------????? ${aaa}"
}
I also thought maybe another way would be for the controller that loads up the gsp which contains the taglib should easily be able to pass a list as a variable down to the taglib, the taglib then takes attrs.newList and represents it as List.
Doing things this way the plugin was complaining about no id, really bizzare since the typical list produced from within plugin looked identical.

How to call to another controller passing all the params in Grails (to update the associated table in the same form)

I'm working with the domain class Alojamiento, and its generated controller and views. The next code works:
I have included in the form of a view another form:
<g:render template="../caracteristicas/form" bean="${params.caracteristicasInstance}" />
Now, the edit action of the controller has:
def alojamientoInstance = Alojamiento.get(id)
def caracteristicasInstance = alojamientoInstance.caracteristicas
[caracteristicasInstance: caracteristicasInstance,
And to the update action of the controller:
def caracteristicasInstance = Caracteristicas.get(id)
caracteristicasInstance.properties = params
caracteristicasInstance.save(flush: true)
As I said, the above code works, but it is not protected against errors, so I'm trying to use the update action of CaracteristicasController (I'm following this approach: http://stuff4j.blogspot.com.es/2011/04/calling-controller-method-from-another.html). The next code does NOT work, but I think it explain itself what I'm trying:
CaracteristicasController caracteristicasController = new CaracteristicasController()
CaracteristicasController.properties = params
CaracteristicasController.params.doNotRedirect = 'true' // See: http://stuff4j.blogspot.com.es/2011/04/calling-controller-method-from-another.html
CaracteristicasController.update()
By the way, the error of Grails is: "Cannot set read-only property: properties"
UPDATE 1
I think I didn't explain something well. I have in _form.gsp 3 embedded _form.gsp (I said in my question 1 to simplify). So when I edit _form.gsp, the others must be updated too. I want to call the update action of the "child" controllers to update the forms, but not move to them. I want to keep being in the "parent" controller so when everything updates, the show.gsp of the "parent" will appear. Do I explain it better now?
Why don't you redirect or chain with all need params?

How can I pre-populate a hidden form field in grails?

I have just gotten started with Grails and I have a very basic application running. I want to pre-populate a hidden form field with a random string.
What is the best way to do this? I have looked at the taglib but I am not sure what the best practice is for this sort of thing. Should I create a class in the src/java or src/groovy folder or is there a better way to get this done?
Lastly, and I know this is a very basic question, but if I do create a class or taglib, how exactly is that called from within the .gsp page?
Thanks!
If your action looks like this
def create() { [orgInstance: new Org(params)] }
it means that a new Org object is passed to your view which can be referenced as orgInstance
Since the model [orgInstance: new Org(params)] is a map, you can simply add another parameter:
def create() { [orgInstance: new Org(params), hiddenValue: 'something random'] }
This can be used in your .gsp in the following way:
<input type="hidden" name="test" value="${hiddenValue}" />
Regarding your other question: a custom taglib is used in the same way as the other Grails-Tags: <g:myTag ...>...</g:myTag> . You can change the namespacegto whatever you like -g` is the default. See the documentation for more details: http://grails.org/doc/latest/ref/Tag%20Libraries/Usage.html

How to invoke custom function within g:if test="..." without providing it (or object instance) to the model?

The background is:
I have layout page main.gsp
I need to conditionally show or hide menu item
Condition evaluation is done by querying database
I don't want to augment each controller so it will evaluate this condition and put result to the model
The issue is:
I'm trying to do something like that
<g:if test="${checkCondition()}"> some html here </g:if>
But it fails saying that checkCondition in undefined.
But this works perfectly:
<mytaglib:checkCondition />
The question is:
What should I do to be able to call my function within
<g:if test="${ expression }">
?
Since you have the tag in a namespace ('mytaglib') you need to call it as a method with that namespace too:
<g:if test="${mytaglib.checkCondition()}"> some html here </g:if>
move the checkCondition() as a static method into a class and import this class in your gsp. you can also define a service class with this method and directly call this serivce method from your gsp. the clearest solution is to define, as you described, your own taglib. within your tag lib you can inject service beans with helper methods and so on.
in your taglib you can do something like
def checkCondition = { attrs ->
// place your condition here
if (session.user.id = 1) {
// show menu
out << "menu"
}
}

Grails: Supplying Data to a Global UI Element

Please pardon this newbie question...
In Grails, if I want a partial to be embedded in a layout so that it appears globally, which requires live data, let's say a list of categories, where is the best place to pull the category data to feed it into the view?
I realize this is a very basic question, but I haven't seen this covered in any tutorials yet.
I started this as a comment to Bill James's answer but I figured it might be longer. Bill suggeseted using groovy code inside ${} to make the template (called partial in Rails) work globally:
<g:each in="${ Category.findAll() }" var="cat" />
But, you should not just add code if you dont feel like it might mess up your tidy xml/html. You can always put it in a closure inside a TagLib and thus make it a Tag. The closure must have no parameters, or an 'attr' parameter, or an 'attr' and 'body' parameters but other signatures are invalid.
class CustomTagLib {
static namespace = 'cus'
def categories = { attr, body ->
g.each( in: Category.findAll(), var: attr?.var ?: 'categories' )
}
}
Then you can use that tag into the template with the namespace you chose:
<cus:categories />
Personally I prefer using tags since most of the time it is a reusable code, so it's better for not violating the DRY principle.
You want to put it in grails-app\views\layouts\main.gsp. That's the default layout that most generated code (and likely most examples that you'll see) will use.
Check out the sitemesh section of the grails documentation.
I think you're trying to ask... "How do I feed the category data to the view when I don't know which action caused the page to render, so the action can't add the data to the model?" If that's so, you can use Groovy code directly in the ${} block, such as:
<g:each in="${ Category.findAll() }" var="cat" />
Note that findAll is added to every Model class, and can be called statically (via the classname, not an instance).
Hope this helps

Resources