Ранее, я упоминала, что помощники (Helper
) Ember'а были введены в версии 1.13. На мой взгляд, помощники одни из самых полезных, но не часто обсуждаемых, функций Ember.
В моей лекции Idiomatic Ember на EmberConf 2016, я в деталях рассказала о хелперах, показывая, как они могут быть использованы для подключения и существенного расширения функционала Handlebars.
Они могут использоваться для декларативной шаблонизации — стиля шаблонизации использующего компонируемые действия (composing actions), и предоставляя шаблонам больше ответственности в отношении презентационный логики.
Вместе с коллегой Marten Schilstra, из DockYard, мы создали аддон ember-composable-helpers. Это пакет декларативных помощников, и с его помощью можно уменьшить количество шаблонного кода в Вашем приложении. Вы можете установить его так:
ember install ember-composable-helpers
Один из моих любимых помощников в аддоне — pipe
(и его closure версия, pipe-action
). Он позволяет декларативно составлять действия в шаблоне, вместо создания множества вариантов в компоненте:
{{perform-calculation
add=(action "add")
subtract=(action "subtract")
multiply=(action "multiply")
square=(action "square")
}}
{{! perform-calculation/template.hbs }}
<button {{action (pipe add square) 2 4}}>Should be 36</button>
<button {{action (pipe subtract square) 4 2}}>Should be 4</button>
<button {{action (pipe multiply square) 5 5}}>Should be 625</button>
Помощник pipe был вдохновлён оператором pipe Elixir'а (|>
), который позволяет написать следующее:
A(B(C(D(E), "F"), "G"), "H")
Как цепочка преобразователей:
E
|> D()
|> C("F")
|> B("G")
|> A("H")
Используя pipe оператор, можно естественным образом выразить как E
передаётся функции D
, затем полученное значение передаётся C
в качестве первого аргумента, и так далее. Я думаю, мы можем согласиться, что pipe версия намного легче для чтения!
Если бы Вы только знали мощь хелперов
Вы можете подумать, что помощник это примитивная KeyWord
конструкция, использующая Ember и HTMLBars для расширения выражений, предоставленных Handlebars.
На самом базовом уровне, Handlebars отвечает за компиляцию hbs
шаблонов в HTML:
<p>{{myText}}</p>
<!-- скомпилируется в: -->
<p>Hello world!</p>
Ember и HTMLBars строится поверх этого, добавляя полезные выражения вроде action
, mut
, get
, и hash
. На самом деле, все знакомые хелперы, которые вы используете (от each
до component
) являются частью HTMLBars!
Ember Helpers работают на более высоком уровне, чем HTMLBars helpers, и могут быть использованы для создания новых выражений в Ember, позволяя эффективно расширить шаблонизацию с собственным поведением.
Всё зависит от обстоятельств
Более опытные или консервативные разработчики могли бы посчитать это опасным: при всей своей полезности для конечных пользователей, он также может открыть возможности для злоупотреблений.
Для примера, в Elixir, макросы могут быть использованы для расширения языка, но не рекомендуется для реального использования. Это было закреплено в отличной книге Chris McCord Метапрограммирование на Elixir – "Правило 1: Не используйте макросы".
К счастью, помощники не настолько мощные как макросы Elixir, и играют важную роль в модели программирования Ember. В отличии от макросов, которые позволяют достучаться до AST, использование Ember помощника для расширения презентационной логики приемлемо пока мы не злоупотребляем этим, и это та особенность, где опыт вступает в игру. Так что используйте хелперы с умом.
Уберите прочь Вашу логику с моего газона
Некоторые люди могут испытывать дискомфорт при использовании аддонов, содержащих помощники, из-за неправильного представления о том, что они привносят слишком много логики в шаблоны, и предпочитают держать их свободными от неё.
В качестве лучшей практики, мы должны воздержаться от сложной логики в шаблонах, а также использования вложенных конструкций вроде этой:
{{#unless (or (and (gte value 0) (lt value 0.0001))
(and (lt value 0) (not allowNegativeResults)))}}
...
{{/unless}}
Вместо этого используйте вычисляемые свойства (computed property).
В то же время, сохранять свои шаблоны на 100% свободными от логики очень тяжело – Вы, вероятнее всего уже используете логические помощники вроде if/else
или unless
. Можно легко упустить из виду тот факт, что количество логики в шаблоне строго не определено.
Назад в будущее
ember-composable-helpers
, на самом деле, не значительно увеличит количество логики в шаблонах, если правильно использовать, он инкапсулирует логику представления внутрь этих помощников, и во многих случаях может помочь Вам ликвидировать избыточный код в компонентах или контроллерах.
Например, Вы могли бы написать что-то подобное в вашем приложении:
import Ember from 'ember';
const {
Component,
computed: { filterBy, setDiff },
set
} = Ember;
export default Component.extend({
activeEmployees: filterBy('employees', 'isActive'),
inactiveEmployees: setDiff('employees', 'activeEmployees')
});
Довольно распространённая практика, иметь "компонент-посредник" для использования в других компонентах. С помощью ember-composable-helpers
можно писать такие конструкции непосредственно в шаблоне, где всё абсолютно понятно:
<h2>Active Employees</h2>
{{#each (filter-by "isActive" engineers) as |employee|}}
{{employee.name}} is active!
{{/each}}
<h2>Inactive Employees</h2>
{{#each (reject-by "isActive" engineers) as |employee|}}
{{employee.name}} is inactive!
{{/each}}
Вы можете думать о компонируемых помощниках как своего рода вычисляемых макро свойствах, которые можно использовать и создавать непосредственно в шаблоне. И поскольку Вы можете создавать суб-выражения в Ember, они могут стать мощной конструкцией для уменьшения шаблонного кода в приложении.
С учетом выше сказанного, помните, не слишком увлекайтесь глубокой вложенностью!
Лучшее решение
Как и любые другие инструменты программирования, важно проявлять здравый смысл и использовать их с умом.
Если Вы можете что-то сделать, не значит, что вы должны.
Хорошо написанный уровень представления(view layer) означает, что шаблоны должны быть декларативными (всё совершенно очевидно), насколько это возможно, а не то, что мы должны избегать логики вообще.
Тем не менее, мы не выступаем за перемещение всей своей логики в шаблон — опять же, количество логики в шаблоне строго не регламетировано.
Если Вы хотите увидеть, как аддон используется, Katherin Siracusa написала отличную статью о том, как она использует ember-composable-helpers
в AlphaSights:
Данный паттерн позволяет выполнять операции над данными и в далнейшем более вспомогательные, краткосрочные действия, постоянно возникающие в нашем приложении. Используя компонируемые хелперы, мы можем сделать это довольно просто, без особого дублирования и, не беспокоясь о нежелательных побочных эффектах.
Вы также можете принять участие в обсуждении на нашем Slack канале #e-composable-helpers
.
Как всегда, спасибо за внимание!