Esko
Esko

Reputation: 29377

How do I inject new tags into a TagLib?

Lets assume that I have the following configuration in my conf/InjectionConfig.groovy file:

x {
    a = { attrs, body -> out << "hello" }
    b = { attrs, body ->  out << "goodbye" }
}

and that I have a simple taglib such as

class XTagLib {
    static namespace = "x"
}

What I want to do is that when I type <x:a /> to any of my views, it would print hello. I've already tried to inject these to the metaclass of the taglib as both property and method but neither seem to work. As an example, here's basically what I'm doing right now in a service:

public void afterPropertiesSet() throws Exception {
    GroovyClassLoader classLoader = new GroovyClassLoader(getClass().classLoader)
    def slurper = new ConfigSlurper(GrailsUtil.environment)
    ConfigObject xConfig
    try {
        xConfig = slurper.parse(classLoader.loadClass('InjectionConfig'))
    }
    catch (e) {
        e.printStackTrace()
    }
    xConfig.x.each({
        if ( !XTagLib.metaClass.hasMetaProperty(it.key) ) {
            XTagLib.metaClass.registerBeanProperty(it.key, { args ->
                def attrs = args[0], body = args[1]
                it.value.call(attrs, body)
            }
        }
    })
}

Am I just doing it wrong or is this even possible currently?

Upvotes: 4

Views: 637

Answers (2)

Victor Sergienko
Victor Sergienko

Reputation: 13485

Well, this

    def shell = new GroovyShell() // or get a GroovyClassLoader
    Class yTagLibClass = shell.evaluate("class YTagLib { static namespace = 'x' }; return YTagLib")

    yTagLibClass.metaClass.a = { attrs, body -> delegate.out << 'blabla' }
    grailsApplication.addArtefact(TagLibArtefactHandler.TYPE, yTagLibClass)

<x:a/> nearly worked for me - registered a tag, except for it didn't output anything. You still need to make the closure resolve out against Grails' taglib's out property.

I don't see a pretty way to do it, as there's no access to instance variables, and out is an instance variable. See Grails source, JspInvokeGrailsTagLibTag.doStartTagInternal() - you might find a way.

EDIT: I added delegate. prefix that should resolve out property of target object. Now I believe I deserve an acceptance :)

Upvotes: 2

Ho&#224;ng Long
Ho&#224;ng Long

Reputation: 10848

What I want to do is that when I type to any of my views, it would print hello

I think there's an alternative way to do what you intend: combine template & tagLib. First, create a template, then add it in your TagLib (with no complex configuration).

In my opinion, it's more simple than your approach.

Please take a look at this tutorial: http://jan-so.blogspot.com/2008/02/example-of-template-and-taglib-with.html

Upvotes: 1

Related Questions