Plantillas

3

Porcentaje completado

En este capítulo:

  • Aprenderemos a usar Spacebars, el sistema de plantillas de Meteor.
  • Crearemos nuestras primeras tres plantillas.
  • Aprenderemos cómo funcionan los gestores de plantilla.
  • Obtendremos un prototipo básico funcional con datos estáticos.
  • Para introducirnos de manera sencilla en el desarrollo con Meteor, adoptaremos un enfoque de afuera hacia adentro, es decir, primero construiremos el envoltorio exterior y luego lo conectaremos al funcionamiento interno de la aplicación.

    Esto implica que, en este capítulo, solo utilizaremos el directorio /client.

    Si todavía no lo has hecho, crea un nuevo archivo main.html dentro del directorio client, rellenándolo con el siguiente código:

    <head>
      <title>Microscope</title>
    </head>
    <body>
      <div class="container">
        <header class="navbar navbar-default" role="navigation"> 
          <div class="navbar-header">
            <a class="navbar-brand" href="/">Microscope</a>
          </div>
        </header>
        <div id="main">
          {{> postsList}}
        </div>
      </div>
    </body>
    
    client/main.html

    Esta será la plantilla principal de la aplicación. Como se puede ver, todo es HTML excepto la etiqueta {{> postsList}}, que es un punto de inserción de la plantilla postsList. Ahora, vamos a crear un par de plantillas más.

    Las plantillas en Meteor

    La aplicación que estamos construyendo va a ser una red social de noticias que estará compuesta de mensajes (en adelante, posts) organizados en listas, y así es como organizaremos nuestras plantillas.

    Vamos a crear el directorio /templates dentro de /client. Aquí pondremos todas nuestras plantillas, pero además, para mantener las cosas ordenadas creamos el directorio /posts dentro de /templates para las plantillas relacionadas con los posts.

    ¿Cómo encuentra nuestros archivos Meteor?

    Meteor es bueno encontrando archivos. No importa en qué lugar pongamos el código dentro de /client, Meteor lo encontrará y lo compilará correctamente. Esto significa que no hay que escribir manualmente rutas para los archivos CSS o JavaScript.

    También significa que se podrían poner todos los archivos en el mismo directorio, o incluso todo el código en el mismo archivo. Pero como, de todas formas, Meteor lo va a compilar todo en un solo archivo minimizado, preferimos mantener las cosas bien organizadas y utilizar una estructura de archivos lo más limpia posible.

    Ya estamos listos para nuestra segunda plantilla. Dentro de client/templates/posts, crea el fichero posts_list.html:

    <template name="postsList">
      <div class="posts">
        {{#each posts}}
          {{> postItem}}
        {{/each}}
      </div>
    </template>
    
    client/templates/posts/posts_list.html

    Y post_item.html:

    <template name="postItem">
      <div class="post">
        <div class="post-content">
          <h3><a href="{{url}}">{{title}}</a><span>{{domain}}</span></h3>
        </div>
      </div>
    </template>
    
    client/templates/posts/post_item.html

    Fíjate en el atributo name="postsList" del elemento template. Este será el nombre que Meteor usará para saber donde va cada plantilla (fíjate que el nombre del fichero no es importante).

    Es el momento de introducir Spacebars el sistema de plantillas de Meteor. Spacebars es simplemente HTML mas tres cosas: inclusiones (también llamadas “partials” o plantillas parciales), expresiones (expressions) y bloques de ayuda (block helpers).

    Las inclusiones usan la sintaxis {{> templateName}} y simplemente le dicen a Meteor que reemplace la inclusión por la plantilla del mismo nombre (en nuestro caso postItem).

    Las expresiones como {{title}} pueden, o bien llamar a una propiedad del objeto actual o bien, al valor de retorno de un ayudante (helper) como el que definiremos más adelante en nuestro gestor de plantilla.

    Los bloques de ayuda son tags especiales para mantener el control del flujo de la plantilla, por ejemplo {{#each}}…{{/each}} o {{#if}}…{{/if}}.

    Ir más lejos

    Si quieres saber más sobre Spacebars puedes consultar la documentación oficial.

    Con estos conocimientos, ya podemos entender cómo van a funcionar nuestras plantillas:

    Primero, en la plantilla postsList iteramos sobre un objeto posts usando un bloque {{#each}}…{{/each}}, y para cada iteración, incluimos la plantilla postItem.

    Pero, ¿de dónde viene el objeto posts?. Buena pregunta. Es un ayudante de plantilla, y puedes pensar en ellos como un cajón o hueco para valores dinámicos.

    La plantilla postItem es bastante sencilla. Solo usa tres expresiones: {{url}} y {{title}} devuelven propiedades, y {{domain}} llama a un ayudante.

    Ayudantes de plantillas

    Hasta ahora hemos estado tratando con Spacebars, que es poco más que HTML con algunas etiquetas extra. A diferencia de otros lenguajes como PHP (o páginas HTML con JavaScript), Meteor mantiene las plantillas y su lógica separadas, de forma que nuestras plantillas por sí mismas no hacen casi nada.

    Para que una plantilla tenga vida, necesita ayudantes. Puedes pensar en ellos como los cocineros que toman los ingredientes (tus datos) y los preparan, antes de entregar el plato terminado (las plantillas) al camarero, que, finalmente, los entrega.

    En otras palabras, mientras la función de las plantillas es mostrar o iterar sobre variables, los ayudantes son los que hacen el trabajo pesado asignando un valor a cada variable.

    ¿Controladores?

    Puede ser tentador pensar que los ficheros que contienen estos ayudantes son una especie de “controlador”. Pero eso sería ambiguo, ya que los controladores (al menos en el sentido de controladores MVC) normalmente tienen un papel diferente.

    Así que hemos decido apartarnos de esa terminología, y simplemente nos referimos a “ayudantes de plantillas“ o “lógica de plantilla” cuando hablamos del código JavaScript que acompaña a las plantillas.

    Para mantener las cosas ordenadas, adoptaremos la convención de nombrar al fichero que contiene la plantilla con el mismo nombre, pero con la extensión .js. Así que vamos a crear un fichero posts_list.js dentro de /client/templates/posts para construir nuestro primer ayudante:

    var postsData = [
      {
        title: 'Introducing Telescope',
        url: 'http://sachagreif.com/introducing-telescope/'
      },
      {
        title: 'Meteor',
        url: 'http://meteor.com'
      },
      {
        title: 'The Meteor Book',
        url: 'http://themeteorbook.com'
      }
    ];
    Template.postsList.helpers({
      posts: postsData
    });
    
    client/templates/posts/posts_list.js

    Si todo está bien, ya se pueden ver los datos en el navegador:

    Nuestra primera plantilla con datos estáticos
    Nuestra primera plantilla con datos estáticos

    Estamos haciendo dos cosas. Primero, creamos algunos datos prototipo en postsData. Normalmente, estos datos vienen de la base de datos, pero como no hemos visto cómo hacerlo todavía (espera al siguiente capítulo), hacemos trampa mediante el uso de datos estáticos.

    Segundo, usamos la función Template.postsList.helpers() para definir un ayudante de plantilla llamado posts que, sencillamente devuelve nuestros datos creados en postsData.

    Y si recuerdas, estamos usando el ayudante posts en nuestra plantilla postsList:

    <template name="postsList">
      <div class="posts page">
        {{#each posts}}
          {{> postItem}}
        {{/each}}
      </div>
    </template>
    
    client/templates/posts/posts_list.html

    Al definir el ayudante posts, conseguimos que esté disponible para usarlo en la plantilla, así que nuestra plantilla será capaz de recorrer el array postData pasando la plantilla postItem para cada uno de sus elementos.

    Commit 3-1

    Añadimos una plantilla básica para recorrer los posts y d…

    El ayudante domain

    De forma similar, crearemos un fichero post_item.js para albergar la lógica de la plantilla postItem:

    Template.postItem.helpers({
      domain: function() {
        var a = document.createElement('a');
        a.href = this.url;
        return a.hostname;
      }
    });
    
    client/templates/posts/post_item.js

    Esta vez el valor de nuestro ayudante domain, no son datos sino una función anónima. Este patrón es mucho más común (y más útil) en comparación con nuestros ejemplos de datos ficticios.

    Mostrando el dominio para cada enlace.
    Mostrando el dominio para cada enlace.

    El ayudante domain coge una URL y devuelve su dominio a través de un poco de magia JavaScript. Pero, ¿de dónde saca esa url la primera vez?.

    Para responder a esta pregunta tenemos que volver a nuestra plantilla posts_list.html. El bloque {{#each}} no solo itera nuestros datos, sino que también establece el valor de this dentro del bloque al objeto siendo iterado.

    Esto significa que entre las dos etiquetas {{each}}, el valor de this es asignado a cada post sucesivamente, y esto se hace extensivo al gestor de la plantilla (post_item.js).

    Ahora entendemos porqué this.url devuelve la URL del post actual. Y más aún, como utilizamos {{title}} y {{url}} dentro de nuestra plantilla post_item.html, Meteor sabe que lo que queremos es this.title y this.url y devuelve los valores correctos.

    Commit 3-2

    Establecemos un ayudante `domain` en `postItem`.

    Magia JavaScript

    Aunque esto no es específico de Meteor, he aquí una breve explicación de la “magia de JavaScript”. En primer lugar, estamos creando un elemento HTML ancla (a) vacío y lo almacenamos en la memoria.

    A continuación, establecemos el atributo href para que sea igual a la URL del post actual (como acabamos de ver, en un ayudante, this es el objeto que se está usando en este momento).

    Por último, aprovechamos de la propiedad hostname del elemento a para devolver el nombre de dominio del post sin el resto de la URL.

    Si todo ha ido bien deberíamos ver una lista de posts en el navegador. Esta lista son solo datos estáticos, lo que, por el momento, no nos permite aprovechar las características de tiempo real de Meteor. ¡Aprenderemos cómo hacerlo en el próximo capítulo!

    Recarga automática

    Probablemente ya habrás notado que no es necesario recargar la ventana del navegador cada vez que cambiamos un archivo de código.

    Esto se debe a que Meteor hace un seguimiento de todos los archivos en el directorio del proyecto, y los actualiza automáticamente en el navegador cada vez que detecta un cambio en alguno de ellos.

    La recarga automática es bastante inteligente, ya que incluso, ¡conserva el estado de la aplicación entre dos refrescos!