что такое директивы в angular
Директивы в AngularJS
Директивы — это ключевая особенность AngularJS. С помощью директив можно добавлять новое поведение существующим HTML элементам, можно создавать новые компоненты. Примерами директив, добавляющих новое поведения для существующих HTML элементов, могут служить input, select, textarea в связке с ngModel, required и т.п. Перечисленные директивы в основном связаны с валидацией форм в AngularJS. Но тема валидации заслуживает отдельной статьи.
Директивы можно и нужно использовать для повышения модульности вашего приложения, выделения обособленной функциональности в компоненты, в том числе и для повторного использования.
Если вы разрабатываете приложение на AngularJS и не создаете директивы, то это уже само по себе немного настораживает. Либо ваше приложение достаточно простое и уложилось в стандартные возможности AngularJS, либо, скорее всего, что-то не так с архитектурой вашего приложения. А если у вас при этом есть работа с DOM-ом в контроллерах или сервисах, то вам однозначно надо разбираться с темой создания директив, т.к. манипуляций с DOM-ом не должно быть нигде, кроме директив.
В данной статье я постараюсь рассмотреть процесс создания собственных директив на нескольких примерах.
Хорошим примером создания директив могут служить репозитории команды AngularUI. В эту команду входят разработчики, не являющиеся сотрудниками Google, но очень хорошо зарекомендовавшие себя в списке рассылки и на stackoverflow. Насколько я могу судить, они создают production-ready компоненты с настройками, покрывающими большую часть вариантов использования. У меня тоже есть репозиторий, в который я выкладываю некоторые свои наработки. Но у меня немного другой подход. Мне больше нравится делать директивы под конкретные варианты использования. AngularJS очень лаконичен. Меньше кода => лучше читаемость => проще поддержка и изменение. Зачем тогда создавать «монструозные» компоненты с кучей настроек? Поэтому рассматривайте эти директивы как отправную точку для создания своих собственных под конкретные нужды. Еще за примерами можно пойти на сайт ngmodules.org, возможно, он сможет стать каталогом различных компонентов для AngularJS.
Итак, базовым документом для разработки своих директив является статья Directives из Developer Guide. Там все расписано очень хорошо и подробно. К этому документу придется возвращаться еще не раз.
Директива-обертка для Tooltip-а из Twitter Bootstrap
Использоваться будет примерно так:
За названием директивы идет фабричная функция, которая должна вернуть описание директивы. В общем случае описание представляет собой объект, полный список полей которого приведен в документации. Но существует упрощенный вариант, когда можно вернуть только postLink функцию. В этому случае директива в дальнейшем может использоваться только как атрибут какого-либо HTML элемента. В этом примере как раз использован упрощенный вариант создания директивы.
Последовательность выполнения фаз для иерархической структуры наглядно показана здесь.
Директива для подсветки кода
‘); pre.append(prettyPrintOne(escape(elem.html().slice(1)), undefined, true)); elem.replaceWith(pre); > >; >);
Директива для подсветки кода с использованием google-code-prettify.
Необходимо, чтобы внутреннее содержимое этой директивы не компилировалось и не линковалось, а просто было обработано google-code-prettify.
Данная директива уже реализована через конфигурационный объект. Рассмотрим директиву построчно.
Директива может использоваться как элемент и как атрибут. В общем случае варианты применения кодируются как ‘EACM’. Можно создать директиву, которая может использоваться как элемент ‘E’, атрибут ‘A’, класс ‘C’, комментарий ‘M’.
Означает, что приоритет на котором объявлена эта директива будет последним приоритетом исполнения. Т.е. будут выполнены только директивы приоритетом выше и с таким же. С таким же приоритетом будут выполнены все директивы, т.к. в рамках одного приоритета порядок исполнения директив не определен.
На этапе компиляции мы извлекаем содержимое элемента, обрабатываем спецсимволы, заменяя их на мнемоники, результат обрабатываем google-code-prettify, обрамляем это все тегом pre и заменяем исходный элемент получившимся.
Вот еще интересные варианты директив, задействующих этап компиляции: ng-if, transclude into an attribute. Оставляйте еще примеры в комментариях, добавлю в пост.
uiPagination
Код достаточно длинный, поэтому сюда вставлять не буду.
Классическая директива с визуальным компонентом.
Ключевая особенность здесь — использование изолированной области видимости (scope).
Статья уже получается достаточно большой, поэтому я не буду подробно останавливаться на деталях и всех возможных вариантах. Они хорошо описаны в документации. Кроме того, рекомендую ознакомиться со статьей The Nuances of Scope Prototypal Inheritance (там хорошие визуализации).
В данном случае cur и total будут двунаправлено привязаны через одноименные атрибуты к области видимости, в которой используется директива, а display будет получать обновления через одноименный атрибут из той же области видимости.
uiGrid
Честно говоря, я все откладывал написание этой статьи, пока не напишу подобную директиву 🙂 Написал статью, смотрю, а она тут уже особо ничего не решает. Но раз уж написана, пусть будет как proof of concept. Можно, конечно, все настройки и через большой объект в атрибуте передавать как в ng-grid, но AngularJS может «круче», более декларативно. Поэтому подобный подход, мне кажется, более в духе AngularJS.
Директивы в Angularjs для начинающих. Часть 1
Как писать директивы?
Директивы в Angularjs задаются вместе с другими конфигурациями модуля следующим образом:
При этом есть два варианта их объявления. Простой и более мощный длинный варианты.
Простой вариант создания директивы
Для того, чтобы написать директиву, которая будет вызываться при указании в HTML разметке, в простейшем случае вам нужно задать некую функцию (она называется Связующей Linking, но об этом чуть позже), возвращаемую фабрикой:
Всё. Директива в примитивном виде у нас готова. Можно переходить к более развернутой форме.
Развернутый вариант
В своей полноценной форме задание директивы выглядит следующим образом:
Все эти свойства довольно тесно друг с другом связаны и переплетены. И для того, чтобы было проще в этом разобраться, их лучше рассматривать некими смысловыми группами.
Link и Compile
Метод Link это та самая функция, которую возвращала фабрика директивы в короткой версии. Здесь надо понять, что в Angularjs процесс компиляции разбит на два этапа:
И при этом как в простейшей версии, так и в расширенной метод Link правильно будет называть postLink, поскольку он выполняется после того, как переменные уже сопоставлены. Рассмотрим примеры.
Сперва, я предлагаю переписать пример простой директивы на манер расширенной.
То есть всё, действительно, работает по-прежнему. Теперь можно усложнить задачу и сделать так, чтобы наша фраза выводилась не посредством прямого взаимодействия с DOM element.text(. ), а внутри директивы interpolate «<<>>»:
В примере выше директива habraHabrNotwork не будет работать корректно, поскольку мы вставляем директиву «<<>>» с переменными в postLink, то есть, когда уже выполнены компиляця и линкование. Иными словами Angularjs даже не знает, что «<<>>» это директива, которая подлежит исполнению.
Другое дело, вторая директива. Там всё на своем месте, мы вставляем шаблон «<<"+attrs.habraHabrNotwork+"+"+attrs.habra+">>» до компиляции, и он успешно проходит рендеринг.
Остановимся немного на методе compile. Он может возвращать, как функцию postLink, так и объект с двумя параметрами: pre и post. Где pre и post это методы preLink и postLink соответственно. Из названия методов может показаться, что речь идет о методах до и после Linkа. Но это не совсем так, эти функции выполняются до и после Link а детей директивы в DOM. На примере:
На этом предлагаю сделать паузу. Если тема интересная, в ближайшие дни постараюсь написать продолжение про области видимости и шаблоны.
Разработка директив angularjs — это просто
AngularJS директивы – это клево
AngularJS является каркасом (фреймворком) для построения web приложений, который позволяет создавать сложные приложения достаточно просто. Одна из его лучших возможностей, это создание директив, которые являются повторно используемыми web компонентами. Это дает возможность создавать новые HTML теги и атрибуты, которые могут динамично отображать контент в ответ на изменение данных, и обновлять сами данные, в случае необходимости.
Это очень высокопроизводительный подход, поскольку он позволяет вам оборачивать сложное взаимодействие с DOM в повторно используемые пакеты кода.
В начале создание директив кажется запутанным.
Пройдет немного времени, и вы поймете, насколько полезны директивы. Встроенные в AngularJS директивы являются прекрасным примером их разработки. Но в первое время, при создании директив возможны некоторые трудности с пониманием их работы. Команда Angular сделала хорошую работу, создав директивы чрезвычайно гибкими и мощными, хотя вся эта мощь дается начинающему не без труда.
В частности, трудно понять, как создать директиву, которая бы реагировала на изменение данных, изменяла данные, реагировала на определенные события или сама их возбуждала. В основном это сводится к одному вопросу:
Как мне взаимодействовать с директивой?
Эта статья призвана объяснить и упростить некоторые из наиболее распространенных проблем, которые могут возникать при создании директив.
Принципы создания директив
Как отображать привязки
Кроме этого, если ваш компонент имеет собственный шаблон, вы можете делать все это в изолированной области видимости.
Как читать и записывать данные
Сначала мы используем = в scope : чтобы сделать scope.toggle доступным в нашей директиве. Хотя это явно не указано нигде внутри директивы, при использовании этого синтаксиса scope.toggle читает и записывает свойство, которое пользователь указал в атрибуте.
Как экпонировать события
Как получить содержимое HTML
Директивы могут иметь любое содержимое html, но, как только вы зададите шаблон, их содержимое меняется на него.
Давайте создадим компонент modal : всплывающее окно с кнопкой закрытия, для которого требуется сохранить его содержимое, заданное в html.
Передача содержимого из директивы шаблону включается очень просто. Чтобы это сделать, просто установите transclude: true :
Для достижения более сложных результатов можно объединять любые методы из этой статьи.