6

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?

cdeszaq
  • 30,869
  • 25
  • 117
  • 173
fabien7474
  • 16,300
  • 22
  • 96
  • 124

5 Answers5

20

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.

Siegfried Puchbauer
  • 6,539
  • 34
  • 24
  • Yes, taglibs are so much cleaner all the way around – mbrevoort Oct 22 '09 at 15:47
  • 1
    see also question http://stackoverflow.com/questions/2510929/problem-calling-grails-service-from-gsp taglib example: http://stackoverflow.com/a/7005752/160799 (looks not very clean to me, though. I prefer solution http://stackoverflow.com/a/1652410/160799 below - still new to Grails but I found no other way for handling display based on access rights for items in a search result list). – Gregor Feb 16 '12 at 15:41
7

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.

Chris King
  • 942
  • 2
  • 10
  • 14
2

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>
1

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.

fabien7474
  • 16,300
  • 22
  • 96
  • 124
1

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

David Tinker
  • 9,383
  • 9
  • 66
  • 98