(Quick Reference)

6.3 Tag Libraries - Reference Documentation

Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith

Version: null

6.3 Tag Libraries

Like Java Server Pages (JSP), GSP supports the concept of custom tag libraries. Unlike JSP, Grails' tag library mechanism is simple, elegant and completely reloadable at runtime.
Como Java Server Pages (JSP), GSP soporta el concepto de librerias de etiquetas personalizadas. No como JSP, el mecanismo de la libreria de etiquetas de Grails es simple, elegante y completamente recargable en tiempo de ejecucion.

Quite simply, to create a tag library create a Groovy class that ends with the convention TagLib and place it within the grails-app/taglib directory:
Simplemente, para crear una libreria de etiquetas, crea una clase de Groovy que termine con la convencion TagLib y coloquela dentro del directorio grails-app/taglib:

class SimpleTagLib {

}

Now to create a tag create a Closure property that takes two arguments: the tag attributes and the body content:
Ahora para crear una etiqueta, crea un Closure de propiedad que tome dos argumentos: los atributos de la etiqueta y el contenido del cuerpo:

class SimpleTagLib {
    def simple = { attrs, body ->

} }

The attrs argument is a Map of the attributes of the tag, whilst the body argument is a Closure that returns the body content when invoked:
El argumento attrs es un Map de los atributos de la etiqueta, mientras que el argumento body es un Closure que regresa el contenido del cuerpo cuando es invocado:

class SimpleTagLib {
    def emoticon = { attrs, body ->
       out << body() << (attrs.happy == 'true' ? " :-)" : " :-(")
    }
}

As demonstrated above there is an implicit out variable that refers to the output Writer which you can use to append content to the response. Then you can reference the tag inside your GSP; no imports are necessary:
Como se demostro arriba, existe una variable implicita out que se refiere al output Writer el cual puede usar para agregar contenido a la respuesta. Entonces puede referenciar la etiqueta dentro de su GSP; no son necesarios los imports:

<g:emoticon happy="true">Hi John</g:emoticon>

To help IDEs like SpringSource Tool Suite (STS) and others autocomplete tag attributes, you should add Javadoc comments to your tag closures with @attr descriptions. Since taglibs use Groovy code it can be difficult to reliably detect all usable attributes.
Para ayudar a los IDEs como SpringSource Tool Suite (STS) y otros para autocompletar los atributos de la etiqueta, deberia de agregar comentarios Javadoc a los closures de su etiqueta con las descripciones @attr. Desde que las taglibs usan codigo de Groovy puede ser dificil detectar de forma viable todos los atributos usables.

For example:
Por ejemplo:

class SimpleTagLib {

/** * Renders the body with an emoticon. * * @attr happy whether to show a happy emoticon ('true') or * a sad emoticon ('false') */ def emoticon = { attrs, body -> out << body() << (attrs.happy == 'true' ? " :-)" : " :-(") } }

and any mandatory attributes should include the REQUIRED keyword, e.g.
y cualquier atributo mandatorio debe de incluir la palabra reservada REQUIRED, por ejemplo:

class SimpleTagLib {

/** * Creates a new password field. * * @attr name REQUIRED the field name * @attr value the field value */ def passwordField = { attrs -> attrs.type = "password" attrs.tagName = "passwordField" fieldImpl(out, attrs) } }

6.3.1 Variables and Scopes

Within the scope of a tag library there are a number of pre-defined variables including:

Dentro del alcance de la libreria de etiquetas hay un numero de variables predefinidas incluidas:

  • actionName - The currently executing action name
  • controllerName - The currently executing controller name
  • flash - The flash object
  • grailsApplication - The GrailsApplication instance
  • out - The response writer for writing to the output stream
  • pageScope - A reference to the pageScope object used for GSP rendering (i.e. the binding)
  • params - The params object for retrieving request parameters
  • pluginContextPath - The context path to the plugin that contains the tag library
  • request - The HttpServletRequest instance
  • response - The HttpServletResponse instance
  • servletContext - The javax.servlet.ServletContext instance
  • session - The HttpSession instance

  • actionName - El nombre de la accion en ejecucion actualmente
  • controllerName - El nombre del controlador en ejecucion actualmente
  • flash - El objeto flash
  • grailsApplication - La instancia GrailsApplication
  • out - El response writer para escribir hacia el output stream
  • pageScope - La referenica al objeto pageScope usado para el rendereo del GSP (ej. el binding)
  • params - El objeto params para obtener los parametros de la peticion
  • pluginContextPath - La ruta del contexto para el plugin que contiene la libreria de etiquetas
  • request - La instancia HttpServletRequest
  • response - La instancia HttpServletResponse
  • servletContext - La instancia javax.servlet.ServletContext
  • session - La instancia HttpSession

6.3.2 Simple Tags

As demonstrated it the previous example it is easy to write simple tags that have no body and just output content. Another example is a dateFormat style tag:

Como se demostro en el ejemplo anterior es facil de escribir etiquetas simples que no tengan cuerpo y solo contenido de salida. Otro ejemplo es la etiqueta de estilo dateFormat:

def dateFormat = { attrs, body ->
    out << new java.text.SimpleDateFormat(attrs.format).format(attrs.date)
}

The above uses Java's SimpleDateFormat class to format a date and then write it to the response. The tag can then be used within a GSP as follows:

El codigo de arriba usa la clase de Java SimpleDateFormat para dar el formato a una fecha y entonces escribirla en la respuesta. La etiqueta puede entonces ser usada dentro del GSP como sigue:

<g:dateFormat format="dd-MM-yyyy" date="${new Date()}" />

With simple tags sometimes you need to write HTML mark-up to the response. One approach would be to embed the content directly:

Con las etiquetas simples a veces necesitara escribir HTML mark-up en la respuesta. Una propuesta podria ser embeber el contenido directamente:

def formatBook = { attrs, body ->
    out << "<div id="${attrs.book.id}">"
    out << "Title : ${attrs.book.title}"
    out << "</div>"
}

Although this approach may be tempting it is not very clean. A better approach would be to reuse the render tag:

A pesar que este propuesta pueda ser tentativa, no es muy limpia. Una propuesta mejor seria el reusar la etiqueta render:

def formatBook = { attrs, body ->
    out << render(template: "bookTemplate", model: [book: attrs.book])
}

And then have a separate GSP template that does the actual rendering.
Y entonces tener una plantilla de GSP separada que haga el rendering actual.

6.3.3 Logical Tags

You can also create logical tags where the body of the tag is only output once a set of conditions have been met. An example of this may be a set of security tags:

Puede tambien crear etiquetas logicas donde el cuerpo de la etiqueta es solo salida una vez que un conjunto de condiciones hallan sido cumplidas. Un ejemplo de esto pueden ser un conjunto de etiquetas de seguridad:

def isAdmin = { attrs, body ->
    def user = attrs.user
    if (user && checkUserPrivs(user)) {
        out << body()
    }
}

The tag above checks if the user is an administrator and only outputs the body content if he/she has the correct set of access privileges:

La etiqueta de arriba checa si el usario es un administrador y solo muestra el contenido del cuerpo si el/ella tiene el conjunto correcto de privilegios de acceso:

<g:isAdmin user="${myUser}">
    // some restricted content
</g:isAdmin>

6.3.4 Iterative Tags

Iterative tags are easy too, since you can invoke the body multiple times:

Las etiquetas iterativas son tambien sencillas, pues puedes invocar el cuerpo multiples veces:

def repeat = { attrs, body ->
    attrs.times?.toInteger()?.times { num ->
        out << body(num)
    }
}

In this example we check for a times attribute and if it exists convert it to a number, then use Groovy's times method to iterate the specified number of times:

En este ejemplo podemos buscar el atributo times y si existe convertirlo en un numero, entonces usar el metodo times de Groovy para iterar en un numero especifico de veces:

<g:repeat times="3">
<p>Repeat this 3 times! Current repeat = ${it}</p>
</g:repeat>

Notice how in this example we use the implicit it variable to refer to the current number. This works because when we invoked the body we passed in the current value inside the iteration:

Note como en este ejemplo usamos la variable implicita it para referirnos al numero actual. Esto funciona porque cuando invocamos el cuerpo le pasamos el valor actual dentro de la iteracion:

out << body(num)

That value is then passed as the default variable it to the tag. However, if you have nested tags this can lead to conflicts, so you should should instead name the variables that the body uses:

Ese valor es pasado entonces como la variable it por defecto hacia la etiqueta. Sin embargo, si has anidado etiquetas esto puede ocasionar conflictos, asi que en ves deberia de nombrar las variables que el cuerpo usa:

def repeat = { attrs, body ->
    def var = attrs.var ?: "num"
    attrs.times?.toInteger()?.times { num ->
        out << body((var):num)
    }
}

Here we check if there is a var attribute and if there is use that as the name to pass into the body invocation on this line:

Aqui checamos si hay un atributo var y si lo hay lo usamos como el nombre para pasarlo dentro de la invocacion del cuerpo en esta linea:

out << body((var):num)

Note the usage of the parenthesis around the variable name. If you omit these Groovy assumes you are using a String key and not referring to the variable itself.

Note el uso del parentesis alrededor del nombre de la variable. Si usted omite esto Grovvy asume que esta usando una llave String y no se esta refiriendo a la variable.

Now we can change the usage of the tag as follows:

Ahora podemos cambiar el uso de la etiqueta como sigue:

<g:repeat times="3" var="j">
<p>Repeat this 3 times! Current repeat = ${j}</p>
</g:repeat>

Notice how we use the var attribute to define the name of the variable j and then we are able to reference that variable within the body of the tag.
Note como usamos el atributo var para definir el nombre de la variable j y entonces somos capaces de referenciar la variable dentro del cuerpo de la etiqueta.

6.3.5 Tag Namespaces

By default, tags are added to the default Grails namespace and are used with the g: prefix in GSP pages. However, you can specify a different namespace by adding a static property to your TagLib class:

Por defecto, las etiquetas son añadidas en el espacio de nombres de Grails y son usadas con el prefijo g: en las paginas GSP. Sin embargo, puede especificar un espacio de nombres diferente añadiendo una propiedad estatica a su clase TagLib:

class SimpleTagLib {
    static namespace = "my"

def example = { attrs -> … } }

Here we have specified a namespace of my and hence the tags in this tag lib must then be referenced from GSP pages like this:

Aqui hemos especificado un namespace de my y por lo tanto las etiquetas en esta libreria deben entonces ser referenciadas desde las paginas GSP asi:

<my:example name="..." />

where the prefix is the same as the value of the static namespace property. Namespaces are particularly useful for plugins.

Donde el prefijo es igual al valor de la propiedad estatica namespace. Los espacios de nombres son particularmente utiles para los plugins.

Tags within namespaces can be invoked as methods using the namespace as a prefix to the method call:

Las etiquetas dentro de los espacios de nombres pueden ser invocadas como metodos usando el espacio de nombre como prefijo para la llamada del metodo:

out << my.example(name:"foo")

This works from GSP, controllers or tag libraries

Esto funciona desde GSP, controlladores o librerias de etiquetas.

6.3.6 Using JSP Tag Libraries

In addition to the simplified tag library mechanism provided by GSP, you can also use JSP tags from GSP. To do so simply declare the JSP to use with the taglib directive:

En adicion al mecanismo simplificado de librerias de etiquetas proveido por GSP, usted tambien puede usar etiquetas de JSP desde GSP. Para hacerlo simplemente declare el JSP que usara con la directiva taglib:

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

Then you can use it like any other tag:

Entonces podra usarla como cualquier otra etiqueta:

<fmt:formatNumber value="${10}" pattern=".00"/>

With the added bonus that you can invoke JSP tags like methods:

Con el extra añadido que puede invocar etiquetas de JSP como metodos:

${fmt.formatNumber(value:10, pattern:".00")}

6.3.7 Tag return value

Since Grails 1.2, a tag library call returns an instance of org.codehaus.groovy.grails.web.util.StreamCharBuffer class by default. This change improves performance by reducing object creation and optimizing buffering during request processing. In earlier Grails versions, a java.lang.String instance was returned.

Desde Grails 1.2, una llamada a la libreria de etiquetas regresa una instancia de la clase org.codehaus.groovy.grails.web.util.StreamCharBuffer por defecto. Este cambio mejora el desempeño reduciendo la creacion de objetos y optimizando la carga durante el proceso de peticion. En versiones anteriores de Grails, una instancia de java.lang.String era devuelta.

Tag libraries can also return direct object values to the caller since Grails 1.2.. Object returning tag names are listed in a static returnObjectForTags property in the tag library class.

Las librerias de etiquetas tambien pueden regresar valores directos de un objeto al que hace la peticion, desde Grails 1.2.. Nombres de etiquetas que regresan objetos son listados con la propiedad estatica returnObjectForTags en la clase de la libreria de etiquetas.

Example:

Ejemplo:

class ObjectReturningTagLib {
    static namespace = "cms"
    static returnObjectForTags = ['content']

def content = { attrs, body -> CmsContent.findByCode(attrs.code)?.content } }