Розширення кутової директиви


114

Я хотів би внести незначні зміни в сторонні директиви (зокрема 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, я заміню свої зміни.

Тож як я можу розповсюджувати цю директиву окремо від цього компонента підключення?


2
Чистий спосіб був би використовувати $provide.decorator(), побачити моя відповідь нижче.
Еліран Малька

Відповіді:


96

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

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

Варіант 2: Ви також можете отримати доступ до області директиви третьої сторони, просто поставивши власну довільно названу директиву на один і той же елемент з нею (якщо при цьому жодна директива не використовує ізолювати область). Всі директиви щодо неізоляції сфери щодо елемента поділять сферу застосування.

Подальше читання: https://github.com/angular/angular.js/wiki/Dev-Guide%3A-Understanding-Directives

Примітка. Моя попередня відповідь стосувалася зміни сервісу третьої сторони, а не директиви.


3
дякую @ sh0ber, це саме те, що мені було потрібно. І ваша попередня відповідь мені також допомогла, щодо: сторонні послуги.
Кайл

Гей, ця відповідь дійсно гарна, але я не можу знайти жодної документації щодо "пріоритетного" властивості для директив. Все, що я знайшов, - це розмиття, на якому написано "ви можете ним скористатися", але не можу знайти реальних прикладів цього.
Ciel

2
@Ciel директива інформація API, мабуть , був перенесений в $compileдокумент тут
Dan

60

TL; DR - gimme tha demo!


     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блоці.

Деякі примітки

  • Було запропоновано просто додати директиву з однойменною назвою, а потім встановити рівень її пріоритетності. Окрім того, що він несемантичний (про що я навіть не знаю, це слово ...), він створює питання, наприклад, що робити, якщо рівень пріоритетності сторонніх директив зміниться?

  • JeetendraChauhan заявив (я ще не перевіряв цього), що це рішення не працюватиме у версії 1.13.


1
Я пропоную вам дати відповідь @ sh0ber (створити іншу директиву лише для передачі подій).
Еліран Малька

2
Швидка примітка про цю відповідь (яка чудово працює): "Директива" в "paneDirective" має мету ;-) У мене знадобився деякий час, перш ніж з'ясувати це: stackoverflow.com/questions/19409017/… , див. відповідь.
Рой Мілдер

2
привіт @EliranMalka перевіри мою планку plnkr.co/edit/0mvQjHYjQCFS6joYJdwK сподіваюся, що це допоможе комусь
Jeetendra Chauhan

1
Посилання на decorator()розірвано (оновлено docs.angularjs.org/api/auto/service/$provide#decorator )
Кріс Браун

1
@EliranMalka так, bindToControllerбуло введено в v1.3. Але зауважте, що це не слід вважати альтернативним рішенням, це стосується лише конкретного випадку, коли оригінальна директива була налаштована із bindToControllerвластивістю. Хороша ідея, я опублікую це як відповідь :)
gilad mayani

8

Хоча це не пряма відповідь на ваше запитання, можливо, ви хочете знати, що остання версія (в головному) http://angular-ui.github.io/bootstrap/ додала підтримку для відключення вкладок. Ця функція була додана через: https://github.com/angular-ui/bootstrap/commit/2b78dd16abd7e09846fa484331b5c35ece6619a2


+1 для голови вгору. добре знати. Я здогадуюсь, кутовий завантажувач bowerstrap та bootstrap компонент angular-ui не синхронізовані.
Кайл

6

Ще одне рішення, коли ви створюєте нову директиву, яка розширює її без зміни оригінальної директиви

Рішення схоже на рішення декоратора:

Створіть нову директиву та введіть як залежність директиву, яку ви хочете розширити

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)
});

Таким чином ви можете використовувати оригінальну директиву та розширену версію в одному додатку


2
Це чудово, якраз те, що мені потрібно було розширити директиву про область ізоляції за допомогою власних змінних !! Я виявив, що angular.extend не поглиблює об'єкти, тому це замінює об'єкт області paneDirective на цей. Альтернативою є angular.merge, який збереже початковий обсяг від PaneDirective та додасть / злить змінні, визначені тут.
mathewguest

1
так, angular.mergeмав би бути використаний, я
оновлю

1

Ось ще одне рішення для іншого сценарію розширення прив’язок до директиви, яка має bindToControllerвластивість.

Примітка: це не альтернатива іншим рішенням, які були запропоновані тут. Він вирішує лише конкретний випадок (не охоплений іншими відповідями), де було створено оригінальну директиву bindToController.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.