Tutorial node.js + express + jquery (II): Generando vistas con Jade

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:

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:

Mockup de la página de Mega Facts

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="https://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:

* { margin: 0; padding: 0 }

h2 {
  margin-bottom: 20px;
}

ul {
  list-style-type: none;
  margin-bottom: 25px;
}

ul#facts 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:

app.get('/', routes.index);

(…)Lo que hacemos es asignar a cada ruta una función que se encargará de gestionarla. En este caso, con app.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:

// 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:

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:

Página de MegaFacts

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

  1. Pingback: Tutorial node.js + express + jquery (I): Creando la aplicación « Koalite's blog

  2. Pingback: Tutorial node.js + express + jquery (III): Usando jQuery « Koalite's blog

  3. Hola, queria avisar que este tuto ya quedo obsoleto con la nueva version del express. Estoy recien empezando, haciendo este tuto, y me di cuenta que ya no funciona correctamente con la nueva version del express. Pues no renderiza el layout, solo el index.
    No busque una solucion, solo reemplace el modulo express, por el que esta en este repo de github.
    Saludos.

  4. Gracias por el aviso, Mauro.

    He actualizado tanto el tutorial como el código en github para ponerlo al día con respecto a la versión de express (a día de hoy, 3.0.0rc3). De todas formas, como bien dices, en el código de github están incluídas las versiones de las librerías (express, underscore, etc.) para las que está preparado el tutorial, por lo que usando ese código debería funcionar siempre que la versión de node instalada sea compatible.

Comentarios cerrados.