Tableless

Busca Menu

Templates client-side com Mustache.js

Seja o primeiro a comentar por

Antes de começarmos, uma pergunta: quem nunca implementou um “template” nos moldes do código abaixo?

html  = '<li class="clearfix">';
html += ' <div class="foto">';
html += '   <a href="' + item.permalink + '">';
html += '     <img src="' + item.thumb + '" width="180" height="124" alt="' + item.titulo + '">';
html += '   </a>';
html += ' </div>';
html += ' <span>';
html += item.titulo;
html += ' </span>';
html += '</li>';

Se você ainda faz isso, chegou a hora de parar.

Neste artigo abordaremos a implementação JavaScript para templates Mustache. A sintaxe já foi portada para diferentes linguagens, incluindo Ruby, Python, PHP e Java. Para uma lista completa, visite o site oficial do projeto.

A principal diferença do Mustache para outras formas de templating no client-side (jQuery Template, por exemplo) é que ele não aceita lógica, como declarações condicionais, loops etc. Pode não parecer, mas isso é muito bom: um template não deveria conter nenhuma lógica, já que é apenas uma camada de apresentação.

Por ser “logic-less”, o Mustache.js é bem enxuto, pesando 8.5kb em sua versão minificada.

Criando um template

Os templates Mustache esperam receber dados no formato JSON. Os dados podem ser textos, variáveis e até mesmo funções. Vamos começar com um exemplo básico onde renderizamos um template de um artigo.

var item = {
      titulo: "Templates client-side com Mustache.js",
      permalink: "http://tableless.com.br/templates-client-side-com-mustache-js"
      thumb: "mustache.jpg",
    },
    output = Mustache.render("<h1>{{title}}</h1><p>{{abstract}}</p>", item);
console.log(output);

O método render é o responsável por retornar o template com os dados formatados. O primeiro parâmetro é o template e o segundo o objeto JSON com os dados que devem ser aplicados.

Os dados armazenados no JSON são representados no template utilizando duas chaves (bigode-bigode) com o nome da propriedade.

Uma boa prática é separar o template do seu código JavaScript armazenando a estrutura do template em uma tag script do tipo “text/template”.

<script id="item-template" type="text/template">
<li class="clearfix">
  <div class="foto">
    <a href="{{ item.permalink }}">
      <img src="{{ item.thumb }}" width="180" height="124" alt="{{ item.titulo }}">
    </a>
  </div>
  <span>{{ item.titulo }}</span>
</li>
</script>

Os dados do template são utilizados buscando o conteúdo HTML da tag.

var item = {
      titulo: "Templates client-side com Mustache.js",
      permalink: "http://tableless.com.br/templates-client-side-com-mustache-js"
      thumb: "mustache.jpg",
    },
    template = document.getElementById('article-template').innerHTML;
    output = Mustache.render(template, item);
console.log(output);

Nos exemplos a seguir, para facilitar a leitura, vamos continuar utilizando os templates diretamente no método render do Mustache.

Lógica?

É verdade que não existem tags para condicionais e loops, mas sua implementação é possível utilizando caracteres especiais nas tags do template.

No exemplo abaixo temos um objeto tableless que armazena um conjunto de artigos. Para realizarmos um loop nos artigos, basta utilizar o caractere ‘#’ seguido do nome da propriedade como uma tag do nosso template. Dentro do bloco #artigos temos acesso às propriedades de cada artigo.

var tableless = {
      'artigos': [
        { 'titulo': 'Templates client-side com Mustache.js' },
        { 'titulo': 'Zepto.js: JavaScript peso-leve' },
        { 'titulo': 'JavaScript: o que fazer e aprender para se tornar um dev melhor?' }
      ]
    },
    output = Mustache.render('{{#artigos}}<li>{{titulo}}</li>{{/artigos}}', tableless);
console.log(output);

A lógica de condicionais é tratada no próprio objeto. Assim como o loop acima, basta adicionarmos o caracatere ‘#’ a uma variável booleana para exibir ou não um conteúdo de acordo com o valor da mesma:

var tableless = {
      'artigos': [
        { 'titulo': 'Templates client-side com Mustache.js', publicado: true },
        { 'titulo': 'Zepto.js: JavaScript peso-leve', publicado: true },
        { 'titulo': 'JavaScript: o que fazer e aprender para se tornar um dev melhor?', publicado: false }
      ]
    },
    output = Mustache.render('{{#artigos}}{{#publicado}}<li>{{titulo}}</li>{{/publicado}}{{/artigos}}', tableless);
console.log(output);

Funções

As tags podem conter funções como valores. Por exemplo, no objeto abaixo, a função buzz soma a quantidade de likes, tweets e comentários de um artigo.

var artigo = {
    'titulo': 'Templates client-side com Mustache.js',
      'likes': 32,
    'tweets': 22,
      'comentarios': 45,
    'buzz': function () {
      return this.likes + this.tweets + this.comentarios;
    }
  },
  output = Mustache.render('<h1>{{titulo}} <small>{{buzz}}</small></h1>', artigo);
console.log(output);

Quando o valor de uma tag é representado por uma função e o caractere ‘#’ é utilizado, a mesma pode retornar uma outra função que recebe dois parâmetros: o texto do bloco do template e uma versão especial do método render para ser executada no contexto do bloco.

var artigo = {
    'titulo': 'Templates client-side com Mustache.js',
    'url': 'http://tableless.com.br/templates-client-side-com-mustache-js',
    'permalink': function () {
      return function (text, render) {
        return '<a href="' + this.url + '" class="permalink">' + render(text) + '</a>';
      }
    }
  },
  output = Mustache.render('<p>{{#permalink}}{{titulo}}{{/permalink}}</p>', artigo);
console.log(output);

Esse tipo de função é chamado de helper, podendo conter lógicas exclusivas da view e evitando a repetição de trechos de template comuns.

Parciais

Outra maneira de evitar repetição é utilizando templates parciais. Parciais são referenciados com o caractere ‘>’ dentro da tag.

var tableless = {
      'artigos': [
        { 'titulo': 'Templates client-side com Mustache.js' },
        { 'titulo': 'Zepto.js: JavaScript peso-leve' },
        { 'titulo': 'JavaScript: o que fazer e aprender para se tornar um dev melhor?' }
      ]
    },
    parciais = {'artigo': '
  • {{titulo}}
  • '}, output = Mustache.render('{{#artigos}}{{>artigo}}{{/artigos}}', tableless, parciais); console.log(output);

    Os templates parciais devem ser informados como terceiro parâmetro do método render e seu valor deve ser um objeto contendo um ou mais templates. A chave informada no objeto é o nome da tag que será utilizada no template principal.

    E tem mais

    Além das funcionalidades apresentadas neste artigo, a biblioteca Mustache.js ainda trás alguns outros benefícios como templates compilados, delimitadores personalizados e seções invertidas. Para saber mais, visite a página do projeto no GitHub.

    E você? Utiliza alguma solução de templating no client-side? Compartilhe nos comentários!

    Publicado no dia