Tutorial node.js + express + jquery (II): Generando vistas con Jade
7 noviembre 2011 express, javascript, jquery, nodejs, tutorial
Actualización (octubre 2015): Este tutorial está actualizado a la versión de express 3.0.0rc3. Si intentas seguirlo con versiones anteriores o posteriores, puede que tengas que ajustar algunas cosas. Para tener información detallada sobre versiones actualizadas de node.js y express, te recomiendo que le eches un vistazo a Express in Action: Node applications with Express and its companion tools, donde se explica de una forma bastante amena cómo crear aplicaciones web usando Node.js y Express.
Este post forma parte de una serie de varios:
- Tutorial node.js + express + jquery (I): Creando la aplicación.
- Tutorial node.js + express + jquery (II): Generando vistas con Jade (esto que estás leyendo).
- Tutorial node.js + express + jquery (III): Usando jQuery.
- Tutorial node.js + express + jquery (IV): Conclusiones y próximos pasos.
- Puedes descargar el código fuente de GitHub.
En la primera parte de este tutorial vimos como instalar los componentes que necesitábamos y cómo crear el esqueleto de la aplicación. En esta segunda parte nos vamos a centrar en la forma en que podemos generar las vistas de nuestra aplicación desde Express utilizando Jade.
Nuestra aplicación de ejemplo
Como siempre es más sencillo ver las cosas con un ejemplo que hablando en abstracto, vamos a definir cómo será nuestra aplicación de ejemplo. La «aplicación» que vamos a desarrollar es una aplicación que nos permita manejar listas de facts, al estilo de los Chuck Norris Facts, Bruce Schneier Facts o Pérez-Reverte Facts. El aspecto de nuestra página principal (y única, ya veremos más adelante porqué), será algo similar a esto:
En la parte izquierda mostraremos una lista de personas de las que conocemos facts. Al pulsar sobre una de ellas mostraremos en la parte central la lista de facts conocidos, permitiendo añadir nuevos facts.
Creando las vistas con Jade
Para generar el html usaremos Jade como View Engine. En este tutorial no pretendo hacer un estudio en profundidad de Jade, así que si quieres saber más te recomiendo que eches un vistazo a la página en github de Jade, aunque actualmente la documentación no es todo lo buena que podría ser.
Cuando generamos la aplicación, en la carpeta views se crearon automáticamente dos ficheros,
layout.jade
e index.jade
. El fichero layout.jade
actúa como página maestra de nuestro sitio web, definiendo la estructura básica de todas las demas páginas. En nuestro caso, vamos a modificar la página por defecto para que tenga el siguiente aspecto:doctype 5 html head title Mega Facts link(rel='stylesheet', href='/stylesheets/style.css') body #container #header h1 Mega Facts block content #footer a(href="http://blog.koalite.com") koalite
Jade utiliza la indentación para crear el esquema del documento, en lugar de emplear etiquetas de inicio y cierre como se hace en html. Además, está diseñado para que su sintaxis sea lo más tersa y minimalista posible. Insisto, si no conoces Jade, sería bueno echarle a un vistazo a su página en github.
Lo que estamos definiendo aquí es la típica estructura de un sitio web con su cabecera (el
div
con id header
), su contenido (el div
con id content
) y su pie (el div
con id footer
). La parte del contenido variará de una página a otra, por lo que será la parte que permitiremos modificar en las páginas que usan este layout.
Para incluir en el layout el contenido de las páginas que lo usan, se referencian a través de etiquetas
block
, como por ejemplo:block content
Esa lína está indicando que, en el lugar en que se aparece, se debe colocar el contenido asociado a ese bloque en las páginas que usan el layout.
Ahora que tenemos listo nuestro layout, vamos a retocar
index.jade
para ajustarla a lo que necesitamos:extends layout block content #left-column.column h2 Elige tu héroe ul#heroes each hero in heroes li(class='hero-name') a(href='#') #{hero} #right-column.column h2 Facts ul#facts label(for="new-fact") Añadir nuevo fact: textarea#new-fact a(id='add-new-fact', href='#') Añadir
Como veis, hace falta indicar el nombre del fichero de layout que se usa en esta página, lo que se hace mediante
extends layout
. Para indicar qué queremos usar para rellenar cada bloque, se usa una sintaxis similar a la empleada para definir el bloque:block content ... aquí va el contenido del bloque content ...
Tenemos un formato preparado para dos columnas, en la que la columna izquierda contiene la lista de personas, y la de la derecha los facts de la persona seleccionada. De momento no aparece ningún fact, en la próxima entrega de este tutorial veremos como se cargan utilizando jQuery.
En la primera columna vemos varias cosas interesantes:
- Las plantillas pueden recibir información externa a la hora de generarse. Es el caso de la variable
heroes
, que contiene los nombres de las personas de las que conocemos facts. - Para iterar sobre una lista de datos, podemos usar la construcción
each
. - Jade soporta string interpolation para referenciar las variables. Para ello, basta con usar
#{variable}
.
Por completar, el archivo css que da formato a la página es éste:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
| * { margin : 0 ; padding : 0 } h 2 { margin-bottom : 20px ; } ul { list-style-type : none ; margin-bottom : 25px ; } ul #fac ts li { margin-bottom : 20px ; } #container { width : 1000px ; margin : 25px auto ; } .column { float : left ; margin-top : 45px ; } #left-column { width : 300px ; } #right-column { width : 700px ; } #right-column textarea { width : 100% ; height : 60px ; margin : 5px auto 0 auto ; } #footer { clear : both ; font-size : smaller ; } |
Añadiendo los datos a las vistas
Acabamos de ver cómo se puede definir la vista pero no hemos resuelto una cuestión crucial: ¿cómo llegan los datos a las vistas? Si recordáis el post anterior, al analizar el esqueleto de aplicación veíamos esto:
1
| app.get( '/' , routes.index); |
(…)Lo que hacemos es asignar a cada ruta una función que se encargará de gestionarla. En este caso, conapp.get('/', routes.index)
estamos configurando que, cuando se acceda a la raíz de la aplicación, se ejecute el método index definido en el objeto routes (…)
El objeto
routes
es en realidad una importación del fichero routes/index.js
, en el cual se exporta la función index
. Lo que estamos haciendo es decirle a Express que cuando llegue una petición GET
a la ruta /
, use la función index
para generar la respuesta.
Vamos a modificar el fichero index.js para que se parezca a esto:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| // TODO: This should be read from a database var heroes = [ { name: 'Chuck Norris' , facts: [ 'No existe la teoría de la evolución, tan sólo una lista de las' + ' especies que Chuck Norris permite vivir. ' , 'Chuck Norris no te pisa un pie, sino el cuello.' , 'Chuck Norris borró la papelera de reciclaje.' ] }, { name: 'Bruce Scheneier' , facts: [ 'Science is defined as mankinds futile attempt at learning ' + 'Bruce Schneiers private key.' , 'Others test numbers to see whether they are prime. Bruce ' + 'decides whether a number is prime.' ] }, { name: 'Arturo Pérez-Reverte' , facts: [ 'Pérez-Reverte se baja música en casa de Ramoncín.' , 'Pérez-Reverte no necesita investigar para escribir novela ' + 'histórica, el pasado cambia conforme teclea en la máquina.' ] } ]; exports.index = function (req, res) { var names = heroes.map( function (p) { return p.name; }); res.render( 'index' , { heroes: names }) }; |
Lo primero que hacemos es definir un array,
heroes
, que va a hacer las veces de base de datos. A continuación, definimos la función index
dentro de las funciones exportadas del módulo.
La función
index
recibe dos parámetros, req
, que representa la petición (request) http realizada por el browser y res
, que representa la respuesta (response) http enviada al browser.
De momento no necesitamos nada de la petición http, por lo que no será necesario acceder al objeto
req
. Usando el objeto res
, indicaremos la vista que queremos generar y los parámetros de esa vista. Para ello se emplea el método render
, que recibe en primer lugar el nombre de la vista ('index'
) y, opcionalmente, un objeto con los datos que queremos pasar a la vista ({ heroes: names }
).
No es necesario indicar la ruta completa ni la extensión del fichero con la vista porque en la configuración inicial de Express ya estábamos indicando el directorio que contenía que las vistas y el view engine, lo que permite a Express inferir todo lo que necesita:
1
2
3
4
5
| app.configure( function (){ app.set( 'views' , __dirname + '/views' ); app.set( 'view engine' , 'jade' ); ... }); |
El objeto que pasamos con datos actúa como modelo (en el sentido MVC) de la vista. En este ejemplo estamos pasando un array de strings con los nombres de las personas de las que tenemos recogidos facts. Son los datos que luego usamos en el
each hero in heroes
que vimos hace un momento al hablar de la generación de html con Jade.
En este punto ya podemos ejecutar la aplicación con
nodemon app.js
y navegando a http://localhost:3000 ver nuestra pantalla inicial:Resumen
Tras las dos primeras partes del tutorial ya hemos visto como crear la aplicación inicial y cómo generar vistas dinámicamente en Express utilizando Jade como View Engine. En la última parte del tutorial tocaremos la parte que nos falta: usaremos jQuery para interactuar con Express a través de AJAX y ver cómo podemos tanto descargar información del servidor, como enviársela.
El código fuente del tutorial completo lo podéis encontrar en https://github.com/jmhdez/Nodejs-Sample.
Siguiente capítulo: usando jQuery.
4 comentarios en “Tutorial node.js + express + jquery (II): Generando vistas con Jade”