-
Notifications
You must be signed in to change notification settings - Fork 14
/
03-templates.md.erb
230 lines (156 loc) · 11.3 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
228
229
230
---
title: Templates
slug: templates
date: 0003/01/01
number: 3
contents: Aprenda sobre a linguagem de templating do Meteor, a Handlebars.|Crie seus primeiros três templates.|Aprenda como os gerenciadores Meteor funcionam.|Tenha um protótipo básico funcionando com dados estáticos.
paragraphs: 46
---
Para facilitar o desenvolvimento em Meteor, nós adotaremos uma abordagem de fora para dentro. Em outras palavras, nós iremos constuir uma casca externa "burra" com HTML/JavaScript primeiro, e então associar com o funcionamento interno de nosso aplicativo no subsequentes trabalhos.
Isto significa que neste capítulo nós apenas nos preocuparemos com o que está acontecendo dentro do diretório /client.
Vamos criar um novo arquivo chamado main.html dentro de nosso diretório /client, e vamos preenchê-lo com o seguinte código:
~~~html
<head>
<title>Microscope</title>
</head>
<body>
<div class="container">
<header class="navbar">
<div class="navbar-inner">
<a class="brand" href="/">Microscope</a>
</div>
</header>
<div id="main" class="row-fluid">
{{> postsList}}
</div>
</div>
</body>
~~~
<%= caption "client/main.html" %>
Este será nosso principal template do aplicativo. Como você pode ver é HTML puro exceto por uma única tag `{{> postsList}}```, a qual é um ponto de inserção para o template postList como logo veremos. Por enquanto, vamos criar mais alguns templates.
### Meteor Templates
No seu âmago, um site de notícias sociais é composto de postagens organizadas em listas, e é exatamente assim que iremos organizar nossos templates.
Vamos criar um diretório `/views` dentro de `/client`. Isto irá ser onde nós colocaremos nossos templates, e para manter as coisas organizadas nós também criaremos `/posts` dentro de `/views` apenas para nossos templates relacionados com postagens.
<% note do %>
### Finding Files
O Meteor é incrível para encontrar arquivos. Não importa onde você colocou o seu código no diretório `/client`, o Meteor irá encontrá-lo e compilá-lo corretamente. Isto significa que você nunca precisará manualmente escrever caminhos para inclusão de arquivos JavaScript ou CSS.
Isto também significa que você poderia muito bem colocar todos os seus arquivos no mesmo diretório, ou ainda todo o seu código em um mesmo arquivo. Mas desde que o Meteor vai compilar tudo em um único arquivo minificado de qualquer forma, é melhor que mantemos as coisas bem organizadas e utilize uma estrutura clara de arquivos.
<% end %>
Nós finalmente estamos prontos para nosso segundo template. Dentro de `client/views/posts`, crie `posts_list.html`:
~~~html
<template name="postsList">
<div class="posts">
{{#each posts}}
{{> postItem}}
{{/each}}
</div>
</template>
~~~
<%= caption "client/views/posts/posts_list.html" %>
E `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/views/posts/post_item.html" %>
Note o atributo `name="postList"` do elemento template. Este é o norme que será utilizado pelo Meteor para acompanhar qual template vai aonde.
É hora de introduzir o sistema de templating do Meteor, o [ Handlebars](http://handlebarsjs.com). Handlebars é simplesmente HTML, com a adição de três coisas: parciais (*partials*), expressões (*expressions*) e blocos de ajuda (*block helpers*).
As *parciais* usam a síntaxe `{{> templateName}}`, e simplemente dizem ao Meteor para substituir a parcial com o template de mesmo nome (no nosso caso `postItem`).
*Expressões* tais como `{{title}}` ou chamam a propriedade do objeto atual, ou retornam o valor de um auxiliar do template como definido no gerenciador atual do template (logo mais sobre isso).
Finalmente, *blocos de ajuda* são tags especiais que controlam o fluxo do template tais como `{{#each}}...{{\each}}` ou `{{#if}}...{{\if}}`.
<% note do %>
### Indo Além
Você pode visitar o [site oficial de Handlebars](http://handlebarsjs.com) ou [este prático tutorial](http://javascriptissexy.com/handlebars-js-tutorial-learn-everything-about-handlebars-js-javascript-templating/) se quiser aprender mais sobre Handlebars.
<% end %>
Armado com este conhecimento, nós podemos facilmente entender o que está acontecendo aqui.
Primeiro, no template `postsList`, nós estamos iterando sobre um objeto `posts` com o bloco de ajuda `{{#each}}...{{\each}}`. Então, para cada iteração nós incluimos o template `postItem`.
De onde este objeto `posts` se origina? Boa pergunta. Se trata na verdade de um ajudante do template, e nós iremos defini-lo quando olharmos para os gerenciadores de template.
O template `postItem` em si mesmo é bem direto. Apenas usa três expressões: `{{url}}` e {{title}} ambas retornando as propriedades do documento, e `{{domain}}` que chama um ajudante do template.
Nós mencionamos "ajudantes do template" bastante ao longo deste capítulo sem realmente explicar o que eles fazem. Mas para consertar isso, primeiro precisamos falar sobre gerentes.
### Gerentes de Template
Até agora nós estávamos lidando com Handlebars, que nada mais é do que HTML acrescido de algumas tags especiais. Diferentemente de outras linguagens de programação como o PHP (ou até mesmo páginas HTML comuns, que podem incluir JavaScript), o Meteor mantém os templates e as lógicas separadas e esses templates não fazem muita coisa por si só.
Para fazer com que eles ganhem vida é necessário um **gerente**. Você pode pensar em um gerente como um chef de cozinha que pega os ingredientes crus (seus dados) e prepara eles antes de entregar o prato finalizado ao garçom (o template) que o apresenta a você.
Em outras palavras, enquanto o papel do template se limita a exibir ou iterar variáveis, o gerente é aquele que faz todo o trabalho pesado atribuindo valores para cada uma dessas variáveis.
<% note do %>
### Gerentes?
Quando nós perguntarmos por aí a outros desenvolvedores Meteor como eles chamam esses "gerentes de template", metade respondeu "controllers" e a outra metade respondeu "aqueles arquivos onde eu coloco meu código JavaScript".
Gerentes não são de fato "controllers" (pelo menos não no sentido de controllers do MVC) e como a sigla "AAOECMCJ" (Aqueles Arquivos Onde Eu Coloco Meu Código Javascript) não é muito atraente, nós acabamos rejeitando as duas opções.
Como ainda precisávamos usar um nome para indicar aquilo a que estávamos nos referindo, nós optamos pelo termo "gerente" como uma alternativa viável já que não tinha um significado relacionado a nenhum outro framework web.
<% end %>
Para simplifcar as coisas, nós iremos adotar a mesma convenção de nomes utilizada para o template, com exceção da utilização da extensão **.js**. Vamos criar o arquivo `posts_list.js` dentro do diretório `/client/views/posts` e começar a definir nosso primeiro gerente:
~~~js
var postsData = [
{
title: 'Introducing Telescope',
author: 'Sacha Greif',
url: 'http://sachagreif.com/introducing-telescope/'
},
{
title: 'Meteor',
author: 'Tom Coleman',
url: 'http://meteor.com'
},
{
title: 'The Meteor Book',
author: 'Tom Coleman',
url: 'http://themeteorbook.com'
}
];
Template.postsList.helpers({
posts: postsData
});
~~~
<%= caption "client/views/posts/posts_list.js" %>
Se você fez tudo certo, algo parecido com isso irá aparecer no seu navegador:
<%= screenshot "3-1", "Nosso primeiro template com dados estáticos" %>
<%= commit "3-1", "Template de listagem de posts e dados estáticos adicionados." %>
Nós estamos fazendo duas coisas aqui. Primeiro estamos colocando alguns dados de teste no array `postsData`. Esses dados normalmente seriam provenientes de um banco de dados, mas como ainda não vimos como acessá-lo (aguarde até o próximo capítulo) nós estamos "trapaceando" usando alguns dados estáticos. Depois estamos usando a função `Template.myTemplate.helpers()` do Meteor para definir um ajudante de template chamado `posts` que simplesmente nos retornará o array `postsData`.
Definir o ajudante `posts` significa que ele agora estará disponível para ser usado pelo nosso template:
~~~html
<template name="postsList">
<div class="posts">
{{#each posts}}
{{> postItem}}
{{/each}}
</div>
</template>
~~~
<%= caption "client/views/posts/posts_list.html" %>
Agora será possível que nosso template itere sobre o array `postsData` e envie cada objeto contido dentro dele para o template `postItem`.
### O valor do "this"
Nós iremos criar agora o gerente `post_item.js`
~~~js
Template.postItem.helpers({
domain: function() {
var a = document.createElement('a');
a.href = this.url;
return a.hostname;
}
});
~~~
<%= caption "client/views/posts/post_item.js" %>
<%= commit "3-2", "Definição do ajudante `domain` no template `postItem`." %>
Desse vez o valor do ajudante `domain` não é um array, mas uma função anônima. Esse pattern é muito mais comum (e mais útil) se comparado aos nossos exemplos com dados de teste anteriores.
<%= screenshot "3-2", "Exibindo os domínios de cada link." %>
O ajudante `domain` recebe uma URL e retorna seu domínio utilizando um pouco da mágica do Javascript. Mas, pra começar, de onde ela pega essa URL?
Para responder a essa pergunta nós precisamos voltar ao nosso template `posts_list.html`. O ajudante `{{#each}}` não apenas itera um array mas também **atribui o valor do `this` dentro do bloco do objeto iterado**.
Isso significa que entre as duas tags `{{#each}}`, cada post é atribuído ao `this` sucessivamente e isso também se aplica ao gerente de template (`post_item.js`).
Agora nós entendemos o porque do `this.url` retornar a URL do post atual. E além disso, se nós usarmos `{{title}}` e `{{url}}` dentro do nosso template `post_item.html`, o Meteor sabe que isso significa `this.title` e `this.url` e retorna os valores corretos.
<% note do %>
### Mágica do Javascript
Embora isso não seja especifíco do Meteor, aqui vai uma breve explicação a respeito dessa pequena "mágica do Javascript" descrita acima. Primeiro, nós estamos criando um elemento HTML de âncora (`a`) vazio e armazenando-o na memória.
Depois colocamos em seu atributo `href` a URL do post atual (como nós já vimos, o `this` corresponde ao objeto sob a qual a ação está acontecendo).
Por último, nós aproveitamos o fato de que o elemento `a` tem uma a propriedade especial chamada `hostname` para recuperar o nome de domínio do link sem o restante da URL.
<% end %>
Se você seguiu tudo corretamente, deverá estar vendo agora uma lista de posts no seu navegador. Essa lista é composta apenas por dados estáticos, portanto ela ainda não tira vantagem dos recursos real-time do Meteor. Nós iremos mostrar como mudar isso no próximo capítulo!
<% note do %>
### Recarregamento Automático de Código
Você deve ter notado que não precisa nem recarregar a janela do seu navegador quando altera um arquivo.
Isso acontece porque o Meteor rastreia todos os arquivos dentro do diretório do seu projeto e automaticamente dá refresh no seu navegador sempre que detecta mudanças em algum desses arquivos.
O recarregamento automático de código do Meteor é bem esperto! Ele até preserva o estado da sua aplicação entre um refresh e outro!
<% end %>