iberck
11/10/2016 - 3:58 AM

Grails custom taglibs

Grails custom taglibs

Argumentos

Se puede enviar un objeto hacia un taglib si el valor del argumento se envía dentro de una expresión, si no se envía como una expresión será de tipo String:

<t:wizardStep booleano="true"/>: Envía un String al taglib

<t:wizardStep booleano="${true}"/>: Envía un java.lang.Boolean al taglib

<t:wizardStep booleano="${us.incorpora.sigrem.StepStatus.COMPLETE}"/>: Envía un objeto enumerado de la clase StepStatus.

Body

Es un closure que contiene el cuerpo del taglib. Para renderizar el contenido, solo hay que llamar al closure como si se tratase de un método: body()

El closure retorna un objeto de tipo StreamCharBuffer (similar a StringBuilder)

Pasar valores al body

Para pasar valores de variables contenidas en el body:

class TestTagLib {

   static namespace = 't'

   def bold = { attrs, body ->
       out << "<b>${body(nombre:'carlos')}</b>"
   }
    
}
<t:bold>hola ${nombre}</t:bold>

Si la variable del body se llama ${it}, se puede enviar al body únicamente el valor:

def repeat = {attrs, body->
    attrs.times?.toInteger()?.times {num->
        out << body(num)
    }
}
<t:repeat times="3">
    <br/>repeat= ${it}
</t:repeat>

Taglibs anidados

Existen 2 formas comunes de utilizar taglibs anidados, una en donde el taglib padre y el taglib hijo son independientes y solo se pone uno dentro de otro porque en ese orden se desea escriba cada taglib el código html que generan.

La otra manera es donde los taglibs dependen uno de otro, la cual se explica a continuación:

El objeto pageScope vive durante el ciclo de vida de una página y se puede utilizar para pasar variables desde un tag padre hacia un tag hijo.

A continuación se muestra un ejemplo en donde el body del tag <t:loading> se asigna al atributo data-loading del tag padre tag1:

TestTagLib.groovy:

class TestTagLib {

   static namespace = 't'

   def tag1 = { attrs, body ->
       def tag1Body = body()
       out << """<b data-loading="${pageScope.loadingBody}">veamos!</b>"""
   }

    def loading = {attrs, body->
        pageScope.loadingBody = body()
    }

}

test.gsp:

<t:tag1>
    'body tag1'
    <t:loading>body loading, yeah!</t:loading>
</t:tag1>
<t:tag1>
    'body tag2'
    <t:loading>body loading2, yeah2!</t:loading>
</t:tag1>
<t:tag1>
    'body tag3'
    <t:loading>body loading3, yeah3!</t:loading>
</t:tag1>

Resultado:

<body>
<b data-loading="body loading, yeah!">veamos!</b>
<b data-loading="body loading2, yeah2!">veamos!</b>
<b data-loading="body loading3, yeah3!">veamos!</b>
</body>

Body condicional

Dependiendo de la condición pinta el body:

def isAdminContenido = { attrs, body ->
    if (SpringSecurityUtils.ifAllGranted('ROLE_ADMIN_CONTENIDO')) {
        out << body()
    }
}

Comentarios

Ayudan al IDE a autocompletar:

@attr nombre REQUIRED descripción

@attr apellido descripción

Retornos

Un taglib puede ser usado en una GSP como un tag ordinario o también puede ser utilizado en expresiones GSP o como funciones dentro de otros taglibs.

La variable out que está disponible dentro del taglib es una implementación de org.codehaus.groovy.grails.web.util.StreamCharBuffer (java.io.Writer) que escribe a un buffer que captura la salida del taglib. Este buffer es el valor de retorno del taglib cuando es utilizado como una función.

Un taglib también puede retornar un objeto. Para indicar que el taglib retorna un objeto hay que escribir el nombre del taglib en el array static returnObjectForTags = []. Cuando un taglib retorna un objeto, éste puede ser utilizado dentro de expresiones o como función de otros taglibs:

Taglib:

class ExampleTagLib {

    static namespace = 't'
    static returnObjectForTags = ['exampleWithReturn']

    def example = { attrs, body ->
    }

    BigDecimal exampleWithReturn = { attrs, body ->
        return 23.65
    }
}

GSP:

1: ${t.example().class} <br/>
2: ${t.exampleWithReturn().class} <br/>

Resultado:

1: class org.codehaus.groovy.grails.web.util.StreamCharBuffer 
2: class java.math.BigDecimal 

Invocación

Invocar un taglib desde un controlador/expresión gsp:

g.createLink(controller: 'user', action: 'show')

Invocar un taglib desde cualquier clase:

def grailsApplication
...

def g = grailsApplication.mainContext.getBean('org.codehaus.groovy.grails.plugins.web.taglib.ApplicationTagLib')
def userShow = g.createLink(controller: 'user', action: 'show')

Interactuar con la propiedad "class" de attrs

attrs.get("class") se refiere al método getClass

attrs.class se refiere a el argumento class enviado al taglib:

if (tooltip) {
    attrs.class = attrs.class?attrs.class + " ":""
    attrs.class += error ? "label-tooltip-error" : "label-tooltip"
}

Enviar atributos del taglib hacia el template

index.gsp:

<t:test class="body-inside" name="apellidos" id="apellidos" />

_taglibcontent.gsp:

<input type="text" ${raw(attrsHtml)} />
class TestTagLib {

   static namespace = 't'

   def test = {attrs, body ->
       def attrsHtml = TagLibUtils.attrsToHtml(attrs)
       out << g.render(template: "/test/taglibcontent", model: [attrsHtml: attrsHtml])
   }

}

Resultado:

<input type="text" class="body-inside" name="apellidos" id="apellidos">

Referencia

Referencia taglibs