В статье, где мы впервые рассмотрели Handlebars (шаблонизатор JavaScript), был работающий пример, но возможно он был недостаточно убедителен в отношении, почему использование Handlebars лучше конкатенации для создания HTML сниппетов.

Затем был еще этот пример с Ajax запросом, возвращающим JSON данные. Там мы также использовали простой JavaScript, но там было уже совсем неприятно. Давайте теперь посмотрим, как мы можем делать те же самые вещи, используя Handlebars.

В предыдущем примере мы получили JSON-ответ со следующим содержимым:

examples/js/data.json

{
   "title" : "Code Maven",
   "description" : "Coding is fun!",
   "articles" : [
       {
          "title" : "Handling user events in JavaScript",
          "url"   : "http://code-maven.com/handling-events-in-javascript"
       },
       {
          "title" : "On-load counter with JavaScript and local storage",
          "url"   : "http://code-maven.com/on-load-counter-with-javascript-and-local-storage"
       }
   ]
}

Мы использовали этот код:

examples/js/ajax.js

function ajax_get(url, callback) {
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
            console.log('responseText:' + xmlhttp.responseText);
            try {
                var data = JSON.parse(xmlhttp.responseText);
            } catch(err) {
                console.log(err.message + " in " + xmlhttp.responseText);
                return;
            }
            callback(data);
        }
    };

    xmlhttp.open("GET", url, true);
    xmlhttp.send();
}

ajax_get('/try/examples/js/data.json', function(data) {
    document.getElementById("title").innerHTML = data["title"];

    var html = "<h2>" + data["title"] + "</h2>";
    html += "<h3>" + data["description"] + "</h3>";
    html += "<ul>";
       for (var i=0; i < data["articles"].length; i++) {
           html += '<li><a href="' + data["articles"][i]["url"] + '">' + data["articles"][i]["title"] + "</a></li>";
       }
    html += "</ul>";
    document.getElementById("text").innerHTML = html;
});


Попробовать здесь!

Используя Handlebars

Функция ajax_get осталась такой же. Она была рассмотрена в статье про Ajax запрос.

Изменения в строках 23-25, где вместо конкатенации HTML по фрагментам, мы получаем шаблон из элемента с id text-template, компилируем исходный код шаблона в функцию template, а затем просто передаем в нее данные, которые мы получили из Ajax запроса. Намного чище, чем раньше, когда мы должны были думать об использовании одинарных кавычек снаружи так, чтобы они не пересекались с двойными кавычками, которые мы хотели использовать для HTML атрибутов.

examples/js/ajax_handlebars.js

function ajax_get(url, callback) {
    xmlhttp = new XMLHttpRequest();
    xmlhttp.onreadystatechange = function() {
        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
            console.log('responseText:' + xmlhttp.responseText);
            try {
                var data = JSON.parse(xmlhttp.responseText);
            } catch(err) {
                console.log(err.message + " in " + xmlhttp.responseText);
                return;
            }
            callback(data);
        }
    };

    xmlhttp.open("GET", url, true);
    xmlhttp.send();
}

ajax_get('/try/examples/js/data.json', function(data) {
    document.getElementById("title").innerHTML = data["title"];

    var source   = document.getElementById('text-template').innerHTML;
    var template = Handlebars.compile(source);
    var html    = template(data);

    document.getElementById("text").innerHTML = html;
});



Сам шаблон находится в HTML файле в теге script.

examples/js/ajax_handlebars.html

<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.1/handlebars.min.js"></script>
 
  <script id="text-template" type="text/x-handlebars-template">
    <h2>{{title}}</h2>
    <h3>{{description}}</h3>
    <ul>
    {{#each articles}}
        <li><a href="{{url}}">{{title}}</a></li>
    {{/each}}
    </ul>
  </script>

<h1 id="title"></h1>
<hr>
<div id="text"></div>

<script src="ajax_handlebars.js"></script>

Try!

Плейсхолдеры для {{title}} и {{description}} это простые значения, которые мы уже видели во введении в Handlebars, но здесь также есть цикл для прохождения по элементам массива. {{#each articles}} начинает цикл по элементам массива, лежащего в ключе articles. Цикл заканчивается, когда мы достигаем инструкции {{/each}}. Внутри цикла мы можем использовать ключи объектов, которые являются элементами массива articles.

Это делает шаблон гораздо чише, чем он был раньше, когда мы использовали конкатенацию.