Расширение директивы Angular

Я хочу внести незначительные изменения в директиву сторонних разработчиков (в частности Angular UI Bootstrap). Я просто хочу добавить в область действия директивы pane:

angular.module('ui.bootstrap.tabs', [])
.controller('TabsController', ['$scope', '$element', function($scope, $element) {
  // various methods
}])
.directive('tabs', function() {
  return {
    // etc...
  };
})
.directive('pane', ['$parse', function($parse) {
  return {
    require: '^tabs',
    restrict: 'EA',
    transclude: true,
    scope:{
      heading:'@',
      disabled:'@' // <- ADDED SCOPE PROPERTY HERE
    },
    link: function(scope, element, attrs, tabsCtrl) {
      // link function
    },
    templateUrl: 'template/tabs/pane.html',
    replace: true
  };
}]);

Но я также хочу сохранить Angular -Bootstrap в актуальном состоянии с Bower. Как только я запустил bower update, я перезапишу свои изменения.

Итак, как я могу расширить эту директиву отдельно от этой компоненты Bower?

Ответ 1

Вероятно, самый простой способ решить эту задачу - создать директиву для вашего приложения с тем же именем, что и директива третьей стороны. Обе директивы будут запущены, и вы можете указать их порядок выполнения, используя свойство priority (сначала запускается более высокий приоритет).

Две директивы будут разделять область действия, и вы можете получить доступ и изменить область действия директивы третьей стороны с помощью вашего директивного метода link.

Вариант 2:. Вы также можете получить доступ к областям директив сторонних разработчиков, просто поместив свою собственную условно названную директиву в один и тот же элемент (при условии, что ни одна из них не использует выделение области). Все директивы неизолированной области действия для элемента будут разделять область действия.

Дальнейшее чтение: https://github.com/angular/angular.js/wiki/Understanding-Directives#extending-directives

Примечание. Мой предыдущий ответ состоял в том, чтобы изменить стороннюю службу, а не директиву.

Ответ 2

TL; DR - демо-версия!


     Big Demo Button     
 


Используйте $provide decorator(), чтобы украсить стороннюю директиву.

В нашем случае мы можем расширить область действия так:

app.config(function($provide) {
    $provide.decorator('paneDirective', function($delegate) {
        var directive = $delegate[0];
        angular.extend(directive.scope, {
            disabled:'@'
        });
        return $delegate;
    });
});

Сначала мы попросим украсить директиву pane, передав его имя, объединенное с Directive в качестве первого аргумента, затем мы извлекаем его из параметра обратного вызова (который представляет собой массив директив, соответствующих этому имени).

Как только мы его получим, мы сможем получить его объект области и продлить его по мере необходимости. Обратите внимание, что все это должно выполняться в блоке config.

Некоторые примечания

  • Было предложено просто добавить директиву с тем же именем, а затем установить ее уровень приоритета. Помимо неземного (даже не слова, я знаю & hellip;), он создает проблемы, например. что, если изменяется уровень приоритета сторонней директивы?

  • JeetendraChauhan заявила (я ее еще не тестировал), что это решение не будет работать в версии 1.13.

Ответ 4

Другое решение, в котором вы создаете новую директиву, которая расширяет его, не изменяя исходную директиву

Решение похоже на решение декоратора:

Создайте новую директиву и введите в качестве зависимости директиву, которую вы хотите расширить

app.directive('extendedPane', function (paneDirective) {

  // to inject a directive as a service append "Directive" to the directive name
  // you will receive an array of directive configurations that match this 
  // directive (usually only one) ordered by priority

  var configExtension = {
     scope: {
       disabled: '@'
     }
  }

  return angular.merge({}, paneDirective[0], configExtension)
});

Таким образом, вы можете использовать оригинальную директиву и расширенную версию в том же приложении

Ответ 5

Вот еще одно решение для другого сценария расширения привязок к директиве с свойством bindToController.

Примечание. это не является альтернативой другим решениям, предлагаемым здесь. Он решает только конкретный случай (не рассматривается в других ответах), где исходная директива была настроена с помощью bindToController.