Директивы в Angularjs для начинающих. Часть 2

от автора

На мой взгляд, директивы являются основной изюминкой декларативного стиля Angularjs. Однако, если открыть комментарии пользователей в разделе официальной документации Angularjs, посвященной директивам, то вы увидите, что самый популярный из них: «Пожалуйста, перепишите документацию, сделайте ее более доступной и структурированной. Начинающему разработчику на Angularjs сложно в ней разобраться» («Please rewrite a clearer well structured documentation of directives., this is not friendly to first time angular developers»). С этим трудно не согласится, документация пока еще сыровата и в некоторых моментах приходится прилагать большие усилия, чтобы разобраться в логике и сути функционала. Поэтому я предлагаю вам свой вольный пересказ данной главы в надежде, что кому-то это позволит сэкономить время, а так же рассчитываю на вашу поддержку и участие в комментариях. Итак, поехали!

Часть 1

  • Как писать директивы?
  • Простой вариант создания директивы
  • Развернутый вариант
  • Link и Compile
Template и TemplateUrl

Продолжая разговор о директивах, надо отметить, что директивы по сути являются модулями, если абстрагироваться от терминологии Angularjs. То есть, в идеале, они должны быть самостоятельным элементом интерфейса со своими функционалом и разметкой. Разметка при этом может задаваться напрямую в параметре Template или храниться в отдельном файле, URL которого указывается в TemplateUrl:

[jsFiddle]

angular.module('helloHabrahabr', [])     .directive('habraHabr', function() {                 return {             template:"<span>Hello Habr!</span>"             /* или */             templateUrl:"helloHabr.html"         }     }); 

helloHabr.html

<span>Hello Habr!</span> 

При этом в случае, если шаблон подгружается, функции Compile и Link выполняются после загрузки.

Scope

Параметр Scope определяет область видимости внутри директивы. Возможно несколько вариантов:

Не указывать scope вовсе. Тогда директива, грубо говоря, работает напрямую в области видимости контроллера. То есть все переменные контроллера равны переменным директивы.

[jsFiddle]

<div ng-app="helloHabrahabr">     <div ng-controller="forExampleController">         {{hello}}                 <span habra-habr></span>      </div>     </div> 

function forExampleController($scope){     $scope.hello="Hello Habr!"; }   angular.module('helloHabrahabr', [])     .directive('habraHabr', function() {                 return {             template:"<input ng-model='hello'>{{hello}}"         }     }); 

Другой вариант. Scope = true. В этом случае, scope будет наследоваться. То есть поля, заданные в родительском scope будут отображаться и в scope директивы, но при этом все изменения будут локальны:

[jsFiddle]

function forExampleController($scope){     $scope.hello="Hello Habr!"; }   angular.module('helloHabrahabr', [])     .directive('habraHabr', function() {                 return {             template:"<input ng-model='hello'>{{hello}}",             scope:true         }     }); 

И наконец, самый интересный вариант. Задать изолированный scope. То есть scope, который по умолчанию абсолютно независим от контекста вызова директивы. Для этого нужно просто указать в качестве scope пустой объект {}:

[jsFiddle]

 angular.module('helloHabrahabr', [])     .directive('habraHabr', function() {                 return {             template:"<input ng-model='hello'>{{hello}}",             scope:{              }         }     }); 

Дальше есть несколько вариантов работы с таким изолированным scope. Но все они сводятся к одному принципу. В объекте, который мы объявили для scope, в качестве имени свойства слева указывается некая переменная директивы, а справа название атрибута DOM c одним из трех символов в начале: @/=/&. То есть вот так:

scope:{       localVar1:"@attrName1",       localVar2:"=attrName2",       localVar3:"&attrName3" } 

Либо еще одни вариант. Не указывать имя атрибута, тогда оно будет равно имени переменной:

scope:{       localVar1:"@", /*localVar1:"@localVar1" */       localVar2:"=",  /*localVar2:"@localVar2" */       localVar3:"&"  /*localVar3:"@localVar3" */ } 

Теперь по порядку. Префикс "@" означает, что локальной переменной будет присвоено значение атрибута:

[jsFiddle]

<div ng-app="helloHabrahabr">         <span habra-habr="hello" some-attr="Hello Habr!"></span>     </div> 

angular.module('helloHabrahabr', [])     .directive('habraHabr', function() {                 return {             template:"{{hello}}",             scope:{                 hello:'@someAttr'             }         }     }); 

Префикс "=" означает, что в атрибуте передается уже не строчка, а имя некоторой переменной в текущем Scope. И локальная переменная будет напрямую с ней связана. То есть изменения переменной как внутри директивы, так и вне отразятся и там, и там:

[jsFiddle]

<div ng-app="helloHabrahabr">     <div ng-controller="forExampleController">         {{hello}}                 <span habra-habr some-attr="hello"></span>      </div>     </div> 

function forExampleController($scope){     $scope.hello="Hello Habr!";  }  angular.module('helloHabrahabr', [])     .directive('habraHabr', function() {                 return {             template:"<input ng-model='hello'>{{hello}}",             scope:{                 hello:'=someAttr'             }         }     }); 

И наконец, последний вариант "&" предполагает, что атрибут содержит некое выражение. К примеру, «c= a+b» или проще «a+b». И теперь ваша локальная переменная становится функцией, в которую можно передавать параметры. Параметры передаются в объекте, ключами которого выступают имена переменных в функции. В конкретном случае, localVar({a:1,b:2}) вернет три.

[jsFiddle]

angular.module('helloHabrahabr', [])     .directive('habraHabr', function() {                 return {             template:"{{helloFn({a:1,b:2})}}",             scope:{                 helloFn:'&someAttr'             }         }     }); 

При этом интересно, что по умолчанию, если не передавать в локальную функцию никаких параметров, переменным будут присвоены значения соответствующих переменных в родительском scope. А если указать переменную -результат, то и она также будет доступна из вне:

[jsFiddle]

<div ng-app="helloHabrahabr">     <div ng-controller="forExampleController">         a={{a}}         b={{b}}         parent's hello={{hello}}                 <span habra-habr some-attr="hello= a+b"></span>      </div>     </div> 

function forExampleController($scope){     $scope.a="Hello";     $scope.b=" Habr!"; }   angular.module('helloHabrahabr', [])     .directive('habraHabr', function() {                 return {             template:"default helloFn={{helloFn()}}\             custom hello={{helloFn({a:'Bye',b:'Habr'})}}",             scope:{                 helloFn:'&someAttr'             }         }     });  

Всем спасибо, продолжение следует.

ссылка на оригинал статьи http://habrahabr.ru/post/180365/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *