Trebla
Trebla

Reputation: 1174

Grails 5 change: how to inject taglib into Controller

In grails 4, if I had plugin-A that defined a taglib with static namespace = "someNamespace", I could reference that in controllers in plugin-B via something like:

render someNamespace.sometag()

In grails 4.0.3, plugin-B had a compile dependency on plugin-A, now it has an implementation dependency. Trying to run the same code, now gives the error:

"No such property: someNamespace for class: com.package.PluginBController"

Attempting to use the same namespace in the application that's running with both plugins A and B works just fine, but calling it from a Controller provided by plugin B fails. Are we missing something with the grails 5 upgrade? Does this need to be injected somehow?

Upvotes: 1

Views: 320

Answers (1)

Jeff Scott Brown
Jeff Scott Brown

Reputation: 27255

Grails 5 change: how to inject taglib into Controller

You can inject a taglib using its bean name like any other bean but there is no good reason to do that. The technique you show in the question is the recommended approach. We effectively add a namespace variable to your controllers which allow you to invoke tag lib implementations as if they were methods. That approach makes more sense than injecting a taglib.

See the project at https://github.com/jeffbrown/treblataglib.

https://github.com/jeffbrown/treblataglib/blob/8f6d46aa2d227ddb34dfa6adfa50d03b270ddd70/app/grails-app/controllers/app/DemoController.groovy

package app

class DemoController {

    def index() {
        render someNamespace.sometag()
    }
}

https://github.com/jeffbrown/treblataglib/blob/8f6d46aa2d227ddb34dfa6adfa50d03b270ddd70/helper/grails-app/taglib/helper/HelperTagLib.groovy

package helper

class HelperTagLib {
    static namespace = 'someNamespace'
    def sometag = { attrs ->
        out << 'This came from HelperTagLib.someTagLib'
    }
}

That appears to work:

~ $ mkdir working                                      
~ $ 
~ $ cd working                                         
working $ 
working $ git clone [email protected]:jeffbrown/treblataglib.git
Cloning into 'treblataglib'...
remote: Enumerating objects: 145, done.
remote: Counting objects: 100% (145/145), done.
remote: Compressing objects: 100% (98/98), done.
remote: Total 145 (delta 23), reused 145 (delta 23), pack-reused 0
Receiving objects: 100% (145/145), 860.12 KiB | 3.41 MiB/s, done.
Resolving deltas: 100% (23/23), done.
working $ 
working $ cd treblataglib                                    
treblataglib (main)$ 
treblataglib (main)$ ./gradlew app:bootRun                              

> Task :app:bootRun
Grails application running at http://localhost:8080 in environment: development
<============-> 95% EXECUTING [26s]
> :app:bootRun

Output:

~ $ http :8080/demo
HTTP/1.1 200 
Connection: keep-alive
Content-Type: text/html;charset=utf-8
Date: Mon, 08 Aug 2022 18:05:14 GMT
Keep-Alive: timeout=60
Transfer-Encoding: chunked
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers

This came from HelperTagLib.someTagLib

EDIT:

A comment below indicates that the problem manifests when a plugin is using a namespaced taglib from another plugin. I have updated the linked project to represent that (https://github.com/jeffbrown/treblataglib/commit/53de85ef7073b8f428ccf0e785097509ed966376).

app depends on another-helper, another-helper depends on helper. helper provides a namespaced taglib. DemoController in another-helper uses that namespaced plugin.

When run the app using Gradle it seems to work. When I build the war, that seems to work as well.

Upvotes: 1

Related Questions