-
Notifications
You must be signed in to change notification settings - Fork 30
/
03-templates.md.erb
227 lines (155 loc) · 10.8 KB
/
03-templates.md.erb
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
---
title: Plantillas
slug: templates
date: 0003/01/01
number: 3
points: 1
photoUrl: http://www.flickr.com/photos/73449134@N04/8194499092/
photoAuthor: Mike Lewinski
contents: 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.
paragraphs: 46
---
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:
~~~html
<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>
~~~
<%= caption "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.
<% note do %>
### ¿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.
<% end %>
Ya estamos listos para nuestra segunda plantilla. Dentro de `client/templates/posts`, crea el fichero `posts_list.html`:
~~~html
<template name="postsList">
<div class="posts">
{{#each posts}}
{{> postItem}}
{{/each}}
</div>
</template>
~~~
<%= caption "client/templates/posts/posts_list.html" %>
Y `post_item.html`:
~~~html
<template name="postItem">
<div class="post">
<div class="post-content">
<h3><a href="{{url}}">{{title}}</a><span>{{domain}}</span></h3>
</div>
</div>
</template>
~~~
<%= caption "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}}`.
<% note do %>
### Ir más lejos
Si quieres saber más sobre Spacebars puedes consultar la [documentación oficial](https://github.com/meteor/meteor/blob/devel/packages/spacebars/README.md).
<% end %>
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.
<% note do %>
### ¿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.
<% end %>
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:
~~~js
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
});
~~~
<%= caption "client/templates/posts/posts_list.js" %>
Si todo está bien, ya se pueden ver los datos en el navegador:
<%= screenshot "3-1", "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`:
~~~html
<template name="postsList">
<div class="posts page">
{{#each posts}}
{{> postItem}}
{{/each}}
</div>
</template>
~~~
<%= caption "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 datos estáticos." %>
### El ayudante `domain`
De forma similar, crearemos un fichero `post_item.js` para albergar la lógica de la plantilla `postItem`:
~~~js
Template.postItem.helpers({
domain: function() {
var a = document.createElement('a');
a.href = this.url;
return a.hostname;
}
});
~~~
<%= caption "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.
<%= screenshot "3-2", "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`." %>
<% note do %>
### 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.
<% end %>
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!
<% note do %>
### 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!
<% end %>