Что такое Transclusion в AngularJS

| Пятница, 10 июня, 2016

Метки AngularJS


AngularJS один из наиболее самых популярных JavaScript-фреймворков на сегодняшний день. Среди всех прочих возможностей AngularJS имеет в своем арсенале такой мощный инструментарий как создание директив. По своей сути, директивы это ничего более, чем просто маркеры в DOM-элементах, которые Javascript использует для манипулирования этими элементами или их содержимым. Программисты, использующие только jQuery регулярно выполняют похожие действия над DOM-элементами, однако AngularJS с помощью директив предлагает более лучшую организацию работы с DOM.

Директивы данная статья описывать не будет, подразумевается, что мы прекрасно понимаем и используем их на практике, а остановимся на таком понятии как transclusion (вставка фрагмента). Для большинства AngularJS-программистов слово transclusion непонятно и нагоняет какую-то мистику в душу и сердце. На самом деле концепция transclusion действительно очень проста, несмотря на то, что некоторые сценарии практического применения могут потребовать некоторого напряжения. Итак, определимся с понятием transclusion и посмотрим, как это работает.

Зачем нужен transclusion?

Рассмотрим ниже разметку HTML и простую директиву.

Html
<div foo>  
    Тут какой-то текст  
</div>
JavaScript
.directive("foo", function() {  
    return {  
        template: "
Это шаблон
" }; })

После компиляции и линковки этой директивы в DOM шаблон заменит содержимое DIV-элемента и на выходе мы получим:

Html
<div foo>  
    <div>Это шаблон</div>  
</div>

Как видите, оригинальный текст потерян и для того чтобы его вернуть, директива должна его клонировать и добавить в DOM. Этот процесс как раз и называется transclusion. Другими словами, transclusion - это метод, с помощью которого директива отображает первоначальный контент, который заменился бы шаблоном.

Первый transclusion-method: ngTranslude

Пример выше имеет несколько вариантов сохранения оригинального содержимого с помощью transclusion. Мы можем использовать директиву ngTransclude или мы можем использовать transclude-функцию, переданную как пятый параметр в link-функцию. Сначала посмотрим, как работает директива ngTransclude. Чтобы нам включить transclusion в примере выше, нам надо в объекте определения директивы (Directive Definition Object) добавить поле transclude и установить его в true, и в шаблоне в нужном месте прописать директиву ngTransclude. Во время процесса линковки директива ngTransclude склонирует оригинальное содержимое и поместит его в DOM как дочерний элемент, того элемента, к которому применена директива ngTransclude.

Html
<div foo>  
    Тут какой-то текст  
</div>
JavaScript
.directive("foo", function() {  
    // возвращаем объект определения директивы  
    return {  
        transclude: true,  
        template: "
Это шаблон
" }; })

Результатом использования директивы ngTransclude будет:

Html
<div foo>  
    <div>Это шаблон</div>  
    <div ng-transclude>Тут какой-то текст</div> 
</div>

Заметим, оригинальное содержимое появилось в том месте, где в шаблоне был DIV-элемент с директивой ngTransclude. И как убеждаемся, идея transclusion довольно проста.

Второй transclusion-method: transclude-функция

Вторым методом, как было упомянуто выше, является использование transclude-функции, которая передается в link-функцию директивы. Рассмотрим код ниже, который достигает той же цели с помощью transclude-функции:

Html
<div foo>  
    Тут какой-то текст 
</div>
JavaScript
.directive("foo", function() {  
    return {  
        template: "
Это шаблон
", transclude: true, link: function(scope, element, attrs, ctrl, transclude) { transclude(function(clone) { element.append(clone); }); } }; })

Transclude-функция передается в качестве пятого параметра и является функцией обратного вызова для выполнения операций над клонированным элементом. В коде выше функция получает клонированное содержимое в виде параметра, а затем добавляет этот клон в DOM. Результатом выполнения такой link-функции является:

Html
<div foo>  
    <div>  
        Это шаблон  
        <div>Тут какой-то текст</div>  
    </div>  
</div>

Результат, конечно, немного отличается из-за другой ссылочности DOM, но цель процесса transclusion достигнута.