Rozszerzenie dyrektywy kątowej

114

Chciałbym wprowadzić niewielką modyfikację w dyrektywie innej firmy (szczególnie w Angular UI Bootstrap ). Chcę po prostu dodać do zakresu panedyrektywy:

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

Ale chcę też, aby Angular-Bootstrap był na bieżąco z Bower. Jak tylko uruchomię bower update, nadpiszę swoje zmiany.

Jak więc mam rozszerzyć tę dyrektywę niezależnie od tego komponentu altanki?

Kyle
źródło
2
Najczystszym sposobem byłoby wykorzystanie $provide.decorator(), zobacz moją odpowiedź poniżej.
Eliran Malka,

Odpowiedzi:

96

Prawdopodobnie najprostszym sposobem rozwiązania tego problemu jest utworzenie dyrektywy w aplikacji o tej samej nazwie, co dyrektywa strony trzeciej. Obie dyrektywy będą działać, a kolejność ich uruchamiania można określić za pomocą prioritywłaściwości (najpierw uruchamiane są o wyższym priorytecie).

Dwie dyrektywy będą miały wspólny zakres, a możesz uzyskać dostęp i zmodyfikować zakres dyrektywy strony trzeciej za pomocą linkmetody swojej dyrektywy .

Opcja 2: Możesz również uzyskać dostęp do zakresu dyrektywy strony trzeciej, po prostu umieszczając własną dowolnie nazwaną dyrektywę na tym samym elemencie co ona (zakładając, że żadna z dyrektyw nie używa zakresu izolowanego). Wszystkie dyrektywy zakresu nieizolowanego w elemencie będą miały wspólny zakres.

Dalsza lektura: https://github.com/angular/angular.js/wiki/Dev-Guide%3A-Understanding-Directives

Uwaga: moja poprzednia odpowiedź dotyczyła modyfikacji usługi innej firmy, a nie dyrektywy.

Dan
źródło
3
dzięki @ sh0ber, właśnie tego potrzebowałem. Twoja poprzednia odpowiedź też mi pomogła, re: usługi innych firm.
Kyle
Hej, ta odpowiedź jest naprawdę dobra, ale nie mogę znaleźć żadnej dokumentacji dotyczącej właściwości „priorytet” dyrektyw. Znalazłem tylko notkę z napisem „możesz tego użyć”, ale nie mogę znaleźć żadnych faktycznych przykładów.
Ciel
2
@Ciel Informacje o dyrektywnym API zostały najwyraźniej przeniesione do $compiledokumentu tutaj
Dan,
60

TL; DR - daj mi demo!


     Big Demo Button     
 


Stosowanie $provide„s decorator()do, dobrze, ozdobić Dyrektywy osoby trzeciej.

W naszym przypadku możemy rozszerzyć zakres dyrektywy w następujący sposób:

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

Najpierw prosimy o udekorowanie panedyrektywy, przekazując jej nazwę połączoną z Directivepierwszym argumentem, a następnie pobieramy ją z parametru wywołania zwrotnego (który jest tablicą dyrektyw pasujących do tej nazwy).

Gdy już go otrzymamy, możemy uzyskać jego obiekt zakresu i rozszerzyć go w razie potrzeby. Zauważ, że wszystko to musi być zrobione w configbloku.

Kilka uwag

  • Sugerowano po prostu dodanie dyrektywy o tej samej nazwie, a następnie ustawienie jej priorytetu. Oprócz tego, że jest niesemantyczny (co nie jest ani słowem , wiem…), stwarza pewne problemy, np. Co, jeśli zmieni się priorytet dyrektywy w sprawie podmiotu trzeciego?

  • JeetendraChauhan stwierdził (nie testowałem go jednak), że to rozwiązanie nie zadziała w wersji 1.13.

Eliran Malka
źródło
1
Proponuję dać odpowiedź @ sh0ber (utwórz inną dyrektywę tylko do emitowania zdarzeń).
Eliran Malka,
2
Krótka uwaga na temat tej odpowiedzi (która działa świetnie), 'Dyrektywa' w 'paneDirective' ma jakiś cel ;-) Zajęło mi trochę czasu zanim to zrozumiałem: stackoverflow.com/questions/19409017/… , zobacz zaakceptowane odpowiedź.
Roy Milder
2
cześć @EliranMalka, sprawdź mój plunkr.co/edit/0mvQjHYjQCFS6joYJdwK mam nadzieję, że to komuś pomoże
Jeetendra Chauhan
1
Link do decorator()jest uszkodzony (zaktualizowano do docs.angularjs.org/api/auto/service/$provide#decorator )
Chris Brown,
1
@EliranMalka tak, bindToControllerzostało wprowadzone w wersji 1.3. Należy jednak pamiętać, że nie należy tego traktować jako rozwiązania alternatywnego, dotyczy to tylko konkretnego przypadku, w którym pierwotna dyrektywa została ustalona wraz z bindToControllerdobrem. Dobry pomysł, opublikuję to jako odpowiedź :)
gilad mayani
8

Chociaż nie jest to bezpośrednia odpowiedź na twoje pytanie, możesz chcieć wiedzieć, że najnowsza wersja (w wersji głównej) http://angular-ui.github.io/bootstrap/ dodała obsługę wyłączania kart. Ta funkcja została dodana przez: https://github.com/angular-ui/bootstrap/commit/2b78dd16abd7e09846fa484331b5c35ece6619a2

pkozlowski.opensource
źródło
+1 za heads up. dobrze wiedzieć. Myślę, że angular-bootstrap Bowera i składnik bootstrap w angular-ui nie są zsynchronizowane.
Kyle
6

Inne rozwiązanie polegające na utworzeniu nowej dyrektywy, która rozszerza ją bez modyfikowania oryginalnej dyrektywy

Rozwiązanie jest podobne do rozwiązania dekoratora:

Utwórz nową dyrektywę i wstrzyknij jako zależność dyrektywę, którą chcesz rozszerzyć

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

W ten sposób możesz używać oryginalnej dyrektywy i rozszerzonej wersji w tej samej aplikacji

kidroca
źródło
2
To świetnie, właśnie to, czego potrzebowałem, aby rozszerzyć dyrektywę zakresu izolowanego o moje własne zmienne !! Zauważyłem, że angular.extend nie kopiuje głęboko obiektów, więc zastępuje to obiekt zakresu paneDirective tym. Alternatywą jest angular.merge, który zachowa oryginalny zakres z PaneDirective i doda / scali zdefiniowane tutaj zmienne.
mathewguest
1
tak, angular.mergepowinien zostać użyty, zaktualizuję przykład
kidroca
1

Oto inne rozwiązanie dla innego scenariusza rozszerzania powiązań do dyrektywy, która ma tę bindToControllerwłaściwość.

Uwaga: nie jest to alternatywa dla innych oferowanych tutaj rozwiązań. Rozwiązuje tylko konkretny przypadek (nieuwzględniony w innych odpowiedziach), w którym ustalono pierwotną dyrektywę bindToController.

gilad mayani
źródło