JavaScript Включаем одни шаблоны Handlebars.js внутрь других шаблонов, или пишем хелпер {{include}}

Handlebars.js — это javascript-шаблонизатор, который дает отличную возможность писать простые и семантически понятные шаблоны, причем можно быть уверенным, что эти шаблоны не свалятся с ошибкой, если одна из переменных шаблона будет не определена, как, например, иногда происходит при использовании встроенного шаблонизатора из Underscore.js. Кроме того, Handlebars.js позволяет нам компилировать шаблоны заранее, не перекладывая задачу по компиляции шаблонов в браузеры пользователей.
Handlebars.js, на первый взгляд, можно назвать примитивным, поскольку он запрещает использовать сложные логические выражения в шаблонах, однако такова концепция этого шаблонизатора и его шарм — ведь шаблоны всегда останутся простыми и понятными. Всю сложную логику следует выносить в специальные функции-хелперы (helpers). Шаблонизатор содержит несколько встроенных хелперов, среди которых {{#each}}, {{#if}} и {{#unless}}, но среди них катастрофически не хватает хелпера {{include}} (наподобие {include} из Smarty), который позволил бы нам включать внутрь одних шаблонов другие шаблоны.

Многие, дочитав до этого места статьи, скажут, что в Handlebars.js есть возможность включать внутрь шаблонов паршелы (partials). Но, к сожаленью, в паршелы нельзя передавать параметры, а возможность передачи параметров была бы очень полезна. Например, я некоторое время назад использовал аналогичную функцию {include} из Smarty для создания шаблонов UI-элементов интерфейса.

К нашему счастью, Handlebars.js с помощью метода registerHelper() позволяет добавлять собственные хеплеры для расширения функциональности шаблонизатора. Используем такую возможность и напишем хелпер {{include}}, который позволит нам включать паршелы с параметрами внутрь шаблонов. Заодно напишем пример такого паршела для чекбокса.

Собственно, код самого хелпера довольно простой и запросто умещается в одну строку.

Handlebars.registerHelper('include', function(template, params) {
  return new Handlebars.SafeString((Handlebars.partials[template])(_.extend({}, this, params.hash)));
});

Сразу оговорюсь, что в проекте помимо Handlebars.js используется еще и связка Backbone.js + Underscore.js, поэтому я использовал функцию _.extend() из Underscore. Если у вас Underscore не используется, то вполне можно заменить _.extend() из Underscore на $.extend() из jQuery.

Ну а теперь пример использования {{include}} в Handlebars.js. Сначала напишем простой шаблон для чекбокса, который будем использовать в нашем проекте.

<script type="text/x-handlebars-template" id="ui-checkbox">
  <div class="ui-checkbox">
    <input type="checkbox" value="1"
           class="ui-checkbox-input"
           {{#if name}}name="{{name}}"{{/if}}>
           {{#if value}}{{value}}{{/if}}
  </div>
</script>

Как видно из кода шаблона, наш чекбокс имеет параметры name и value. Перед тем, как использовать наш паршел, нужно откомпилировать шаблон с помощью метода Handlebars.compile() и зарегистрировать его с помощью метода Handlebars.registerPartial().

Handlebars.registerPartial('checkbox', Handlebars.compile($('#ui-checkbox').html()));

На этом все приготовления окончены, и мы можем легко и просто использовать наш паршел для чекбокса внутри другого шаблона, например, внутри шаблона для формы входа на сайт:

<script type="text/x-handlebars-template" id="logon">
  <form class="js-logon-form">
    ...
    <div class="b-logon-form-field">
      {{include "checkbox"
          name = "RememberMe"
          value = "запомнить меня"
      }}
    </div>
    ...
  </form>
</script>

В качестве значений параметров {{include}} можно также передавать и переменные, которые доступны внутри шаблона.

В целом, Handlebars.js отлично подходит для шаблонизации на стороне клиента. Скачать js-файл с шаблонизатором можно из репозитория на GitHub.