Grails custom taglibs
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
.
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)
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>
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>
Dependiendo de la condición pinta el body:
def isAdminContenido = { attrs, body ->
if (SpringSecurityUtils.ifAllGranted('ROLE_ADMIN_CONTENIDO')) {
out << body()
}
}
Ayudan al IDE a autocompletar:
@attr nombre REQUIRED descripción
@attr apellido descripción
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
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')
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"
}
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">