Создание директив в angular.js
Рубрика: Программирование -> Angular.JS -> JavaScript
Метки: framework | JavaScript | web | директивы | программирование
Просмотров: 12376
Продолжаю на работе терзать и наслаждаться возможностями angular.js. Сегодня мне потребовалось подключить к своему проекту плагин DatePicker из пакета jQuery UI. Заповеди angular.js диктуют использовать в представлении директивы, а не хаотичной раскиданный JavaScript код. Следовательно, вот так просто воспользоваться возможностями плагина DatePicker не получится. Точней получится, но делать это ни в коем случае нельзя, ибо это идет в разрез с идеологией angular.js. К счастью, пойти правильным путем ничуть не сложней. Достаточно написать собственную директиву и использовать в разных участках приложения. Под катом я разберу процесс написания директивы для angular.js максимально подробно.
За основу возьмем заготовку проекта – «angular-seed». Склонируй ее из GIT и приготовься вносить изменения. Поскольку конечной целью будет подключение компонента DatePricker, нам потребуется добавить библиотеку jQuery UI к проекту. Загружаем все необходимое с официального сайта библиотеки (или ставим через bower), распихиваем в соответствующие директории проекта и подключаем все это добро в «index.html»:
<link rel="stylesheet" href="css/jquery-ui-1.9.2.custom.css" />
<script src="js/jquery-1.8.2.js"></script>
<script src="js/jquery-ui.js"></script>
Создаем директиву
Код директивы будем писать в файле «directives.js». Открываем файл и пишем в него код:
directive('myDatepicker', function() {
return {
require: 'ngModel',
link: function (scope, element, attrs, ngModelCtrl) {
$(function() {
element.datepicker({
showOn: 'both',
changeYear: true,
changeMonth: true,
dateFormat: 'dd.mm.yy',
maxDate: '+1Y',
yearRange: '1920:2015',
onSelect:function (dateText, inst) {
ngModelCtrl.$setViewValue(dateText);
scope.$apply();
}
});
});
}
}
});
Если говорить кратко, то в этой директиве происходит подключение плагина DatePicker. Правда, меня, когда я впервые увидел подобную конструкцию, краткий ответ не устроил. Да, мы видим, что большую часть этого листинга занимает конструктор DatePicker, но почему он записывается именно в функции link, с кучей параметров? Об этом расскажу ниже.
Зачем нужны директивы в angular.js
Как ты уже знаешь, директивы необходимы для расширения функционала и поведения существующих html-элементов. Например, мы хотим, чтобы список у элемента управления «select» выпадал вверх, а не вниз. Мы можем это сделать средствами jQuery прямо в коде, но это будет НЕ angular-way. Правильней оформить этот код в виде универсальной директивы, и в дальнейшем использовать ее там, где это необходимо. Директивы – это шаг в сторону модульности и повторного использования кода.
Если ты сомневаешься в целесообразности создания директивы в определенных случаях, то задай себе пару контрольных вопросов:
Наличие положительного ответа на один из перечисленных выше вопросов - гарантия плохой архитектуры и отсутствие понимания идеологии angular. Такие вещи нужно сразу присекать.
Ок, возвращаемся к нашему коду. Чтобы начать использовать директиву ее необходимо зарегистрировать. Регистрация новой директивы выполняется с помощью метода directive(). Он принимает два параметра:
- name (string, object) – название директивы в верблюжьим (camel-case) стиле. Применительно к нашему коду это «myDatepicker».
- directiveFactory (function(), array) - функция-фабрика (factory function). Эта функция должна вернуть объект с настройками для сервиса $compile, отвечающий за компиляцию HTML/DOM в шаблон. Впоследствии он создаст функцию, связывающую skope и наш шаблон.
Теперь посмотрим на настройки объекта, который будет возвращать наша функция-фабрика. Полный список возможных настроек можно посмотреть в официальной документации. В своем примере я использую лишь:
function link(scope, iElement, iAttrs, controller, transcludeFn){}
В качестве параметров применяются:
- scope – область видимости. Будет использоваться директивой для регистрации обработчиков событий (в терминологии angular – watches);
- iElement – экземпляр элемента, в котором будет использоваться директива;
- iAttrs – экземпляр атрибутов элемента;
- ctrl – экземпляр контроллера. Необходимо указывать, если одна из директив элемента, определяет контроллер. В нашем случае в роли контроллера будет выступать ngModelController.
- transcludeFn – признак трансклюзии. Об этом параметре я расскажу в отдельном посте.
В рассматриваемом примере я опустил пятый вариант и сократил определении link-функции до:
function (scope, element, attrs, ngModelCtrl)
В теле функции описывается стандартный конструктор элемента DatePicker. Параметры рассматривать не буду, т.к. отношения к angular они не имеют. Затрону лишь определение обработчика onSelect (). Он должен срабатывать во время выбора в календаре какой-нибудь даты и передавать результат пользовательского выбора в scope.
В теле метода вызывается метод $setViewValue, обновляющий. В качестве параметра метод принимает значение, полученное из представления. В моем случае – это дата, выбранная в DatePicker. После изменения значения нам необходимо оповестить об этом $scope с помощью метода $apply().
Тестируем директиву
Директива полностью готова к применению. Подключение к произвольному элементу ввода выполняется следующим образом:
<input ng-model="myDateOfBirth" my-datepicker />
Если никаких ошибок допущено не было, то ты увидишь возле элемента ввода кнопку для вызова календаря. Аналогичное действие будет выполняться и при клике мышкой по элементу ввода.
На этой самой ноте мой рассказ заканчивается. Если у тебя есть вопросы – задавай их мне в комментариях. Постараюсь помочь.
2014-04-12 в 01:40:44
Как-то сложно выглядит все в вашем angular'е. Мне проще на jquery делать динамику. Я пробовал делать директиву, но забросил, не хрена не работало. Попробую по твоей заметке.
2014-04-13 в 10:45:46
К нему нужно просто привыкнуть. После jquery все выглядит сверх сложно, но чтение документации и практика побеждает любые трудности.
2014-04-14 в 00:19:12
Поддерживаю Andry. После jquery понимаешь, что в angular'е вообще ни фига не понятно. Такое ощущение, что angular придумали какие-то внеземные цивилизации. =)
2014-04-14 в 02:23:33
2Роман,
Да, на первых порах мозг выносит :-) Дело привычки.
2014-04-14 в 02:24:12
Кстати, knockout в этом плане намного легче. Если не получается с angular, то можно посмотреть на knockout =)