6.3 Tag Libraries - Reference Documentation
Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith
Version: null
Table of Contents
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
Simplemente, para crear una libreria de etiquetas, crea una clase de Groovy que termine con la convencion TagLib and place it within the grails-app/taglib directory:
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
El argumento 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:
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
Como se demostro arriba, existe una variable implicita 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:
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 withPara 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@attrdescriptions. Since taglibs use Groovy code it can be difficult to reliably detect all usable attributes.@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 namecontrollerName- The currently executing controller nameflash- The flash objectgrailsApplication- The GrailsApplication instanceout- The response writer for writing to the output streampageScope- A reference to the pageScope object used for GSP rendering (i.e. the binding)params- The params object for retrieving request parameterspluginContextPath- The context path to the plugin that contains the tag libraryrequest- The HttpServletRequest instanceresponse- The HttpServletResponse instanceservletContext- The javax.servlet.ServletContext instancesession- The HttpSession instance
actionName- El nombre de la accion en ejecucion actualmentecontrollerName- El nombre del controlador en ejecucion actualmenteflash- El objeto flashgrailsApplication- La instancia GrailsApplicationout- El response writer para escribir hacia el output streampageScope- La referenica al objeto pageScope usado para el rendereo del GSP (ej. el binding)params- El objeto params para obtener los parametros de la peticionpluginContextPath- La ruta del contexto para el plugin que contiene la libreria de etiquetasrequest- La instancia HttpServletRequestresponse- La instancia HttpServletResponseservletContext- La instancia javax.servlet.ServletContextsession- 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
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 style tag:
dateFormat:def dateFormat = { attrs, body ->
out << new java.text.SimpleDateFormat(attrs.format).format(attrs.date)
}
The above uses Java's
El codigo de arriba usa la clase de Java SimpleDateFormat class to format a date and then write it to the response. The tag can then be used within a GSP as follows:
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
En este ejemplo podemos buscar el atributo times attribute and if it exists convert it to a number, then use Groovy's times method to iterate the specified number of times:
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
Note como en este ejemplo usamos la variable implicita 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:
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
Ese valor es pasado entonces como la 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:
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
Aqui checamos si hay un atributo var attribute and if there is use that as the name to pass into the body invocation on this line:
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
Note como usamos el atributo 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.
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
Por defecto, las etiquetas son añadidas en el espacio de nombres de Grails y son usadas con el prefijo g: prefix in GSP pages. However, you can specify a different namespace by adding a static property to your TagLib class:
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
Aqui hemos especificado un namespace of my and hence the tags in this tag lib must then be referenced from GSP pages like this:
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
Donde el prefijo es igual al valor de la propiedad estatica namespace property. Namespaces are particularly useful for plugins.
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
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 directive:
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
Desde Grails 1.2, una llamada a la libreria de etiquetas regresa una instancia de la clase 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.
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
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 property in the tag library class.
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
}
}
