Como tudo começou
Eu queria criar um componente como um modelo em um pacote de meteoros. Como exemplo, escolhi um selecionador de data.
É bastante simples, mas para algumas coisas eu tive que pesquisar.
Para obter todas as peças necessárias, aqui está o package.js
Package.onUse(function (api) {
api.versionsFrom('1.1.0.2');
api.use(["templating", "underscore", "jquery", "twbs:bootstrap", "reactive-var"]);
api.addFiles(['moment/moment.js', 'moment/fr.js', 'date-pick.html', 'date-pick.js', 'date-pick.css'], 'client');
});
Tive um problema com o pacote moment.js. É difícil adicionar localidades. É por isso que ele é adicionado como arquivos explicitamente.
Tudo está disponível no github
O complicado era acessar as variáveis do template nas funções auxiliares. Sendo um selecionador de data, duas informações são necessárias para todo o modelo
- O mês a ser exibido
- A data selecionada
Na primeira versão, eu simplesmente as defini como variáveis globais na parte superior do js
arquivo.
var now = new ReactiveVar();
var selectedDate = new ReactiveVar();
Isso provou ser uma má ideia, pois eles não fazem parte da instância do modelo e, portanto, se o modelo for usado duas vezes, a primeira instância não funcionará.
Então, adicionei as variáveis ao data
atributo do template no created
callback: o this
objeto é a instância do template.
Template.datePick.created = function () {
this.data.now = new ReactiveVar(this.data.initial ? moment(this.data.initial) : moment());
this.data.selectedDate = new ReactiveVar(this.data.now.get().clone());
console.log("template created");
}
Acessando dados de modelo em ajudantes
Mas então surgiu a questão de acessar essas variáveis nos ajudantes.
Acontece que é bastante fácil, mas você precisa fazer algo especial no modelo.
Quando você usa um auxiliar fora de qualquer bloco with
ou each
, this
é igual a . Mas se você fornecer um contexto de dados para seu ajudante, não há como acessar a propriedade de dados do modelo.templateInstance.data
exemplo 1: ajudante com contexto de dados de modelo
O primeiro elemento do modelo é a data selecionada, que, quando clicada, acionará o menu suspenso do selecionador de data
<span class="dropdown-toggle" type="button" id="datePicker" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="true">
{{selectedFormatedDate}}
</span>
O ajudante é definido assim:
selectedFormatedDate: function(){
if(this.selectedDate.get())
return this.selectedDate.get().format(this.format || "DD.MM.YYYY");
else
return "Date Picker";
}
Como você pode ver, a propriedade de dados do modelo selectedDate
pode ser acessada nothis
exemplo 2: auxiliar com contexto de dados próprio
Mas isso não funciona dentro de um {{#each...
Ao listar os dias, a data selectedDate
e a data exibida no momento precisam ser comparadas para saber qual célula precisa ser destacada.
Isso é feito assim:
<tbody>
{{#each weeks}}
<tr>
{{#each days}}
<td class="{{class}} {{isSelected ../..}}">{{day}}</td>
{{/each}}
</tr>
{{/each}}
</tbody>
Existem dois loops:
- passar por todas as semanas
- dentro de cada semana passe os dias
Ao exibir os dias, uma classe de destaque é adicionada ao dia selecionado. Mas como o contexto de dados é o day
objeto da semana, não temos acesso à propriedade de dados do template.
O truque é passar a propriedade de dados do modelo como um parâmetro. Isso é feito com o ../..
que diz ao Blaze para passar como parâmetro o contexto de dados dos dois níveis acima.
O auxiliar pode ser definido da seguinte forma:
isSelected: function(template){
if(this.moment){
return this.moment.isSame(template.selectedDate.get()) ? "selected-date" : "";
}
}
e o contexto de dados atual em this
pode ser comparado ao contexto de dados do modelo em template
.
Conclusão
Está tudo documentado, claro, mas eu ainda precisava de algum tempo para descobrir.