Как делать обратные вызовы из директив

В документации по angular опущены многие интересные моменты не очевидные для новичков. Один из таких - как правильно передать функцию обратного вызова в директиву.

Предположим что у вас есть директива которая отображает список элементов:

<op-items items="items"></op-items>  

Определение директивы выглядит так:

angular.module('myModule').directive('opItems', () => {  
  return {
    restrict: 'E'
    scope: {
      items: '='
    },
    template: `<ul>
      <li ng-repeat="item in items">{{item.title}}</li>
    </ul>`
  };
});

Теперь мы хотим чтобы элементы в списке можно было удалять. Для этого в шаблон opItems добавим соответствующую кнопку.

<li ng-repeat="item in items">  
  {{item.title}}
  <button ng-click="onDelete({item: item})">×</button>
</li>  

Теперь можно в контроллер директивы добавить метод onDelete и удалять элемент из списка. Но такой подход приводит к плохим последствиям. Более правильно нотифицировать того кто предоставил список о том что нужно удалить элемент.

Для этого в параметры директивы добавим еще один параметр с типом expression:

scope: {  
  items: '=',
  onDelete: '&'
}

И изменим родительский шаблон:

<op-items items="items" on-delete="onDelete(item)"></op-items>  

Теперь можно в родительском контроллере добавить метод onDelete в котором обработать событие удаления элемента. Обратите внимание что в директиве opItems методу передается объект куда вложен item onDelete({item: item}). Этот объект становится скоупом для метода onDelete(item) когда тот выполняется.

Таким образом мы сделали функцию обратного вызова не написав лишнего кода и не нагрузили директиву лишними знаниями о том как удалять элементы из списка. А с angular 1.5 можно заменить тип связывания параметра items с двунаправленного на однонаправленное. Это более четко обозначит интерфейс директивы и улучшит производительность.