Erweiterung der Winkelrichtlinie

114

Ich möchte eine geringfügige Änderung an einer Direktive eines Drittanbieters vornehmen (insbesondere Angular UI Bootstrap ). Ich möchte lediglich den Geltungsbereich der paneRichtlinie erweitern:

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

Aber ich möchte Angular-Bootstrap auch mit Bower auf dem neuesten Stand halten. Sobald ich renne bower update, werde ich meine Änderungen überschreiben.

Wie kann ich diese Richtlinie getrennt von dieser Laubenkomponente erweitern?

Kyle
quelle
2
Der sauberste Weg wäre zu verwenden $provide.decorator(), siehe meine Antwort unten.
Eliran Malka

Antworten:

96

Der wahrscheinlich einfachste Weg, dies zu lösen, besteht darin, in Ihrer App eine Direktive mit demselben Namen wie die Direktive eines Drittanbieters zu erstellen. Beide Anweisungen werden ausgeführt, und Sie können ihre Ausführungsreihenfolge mithilfe der priorityEigenschaft angeben (zuerst wird eine höhere Priorität ausgeführt).

Die beiden Direktiven teilen sich den Geltungsbereich, und Sie können über die linkMethode Ihrer Direktive auf den Geltungsbereich der Direktive eines Drittanbieters zugreifen und diesen ändern .

Option 2: Sie können auch auf den Geltungsbereich einer Drittanbieter-Direktive zugreifen, indem Sie einfach Ihre eigene willkürlich benannte Direktive auf dasselbe Element setzen (vorausgesetzt, keine der Direktiven verwendet den isolierten Geltungsbereich). Alle nicht isolierten Bereichsanweisungen für ein Element teilen sich den Bereich.

Weiterführende Literatur: https://github.com/angular/angular.js/wiki/Dev-Guide%3A-Understanding-Directives

Hinweis: Meine vorherige Antwort betraf das Ändern eines Drittanbieter-Dienstes, nicht einer Direktive.

Dan
quelle
3
danke @ sh0ber, das ist genau das was ich brauchte. Und Ihre vorherige Antwort hat mir auch geholfen, bezüglich der Dienste von Drittanbietern.
Kyle
Hey, diese Antwort ist wirklich gut, aber ich kann keine Dokumentation über die Eigenschaft "Priorität" für Direktiven finden. Alles, was ich gefunden habe, war ein Klappentext mit der Aufschrift "Sie können es verwenden", aber keine tatsächlichen Beispiele dafür.
Ciel
2
@Ciel Die Richtlinie API info hat sich offenbar auf die verschoben worden $compiledoc hier
Dan
60

TL; DR - gib mir die Demo!


     Big Demo Button     
 


Verwenden Sie $provide's decorator(), um die Direktive des Dritten zu dekorieren.

In unserem Fall können wir den Geltungsbereich der Richtlinie folgendermaßen erweitern:

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

Zuerst fordern wir an, die paneDirektive zu dekorieren, indem wir ihren Namen übergeben, der Directiveals erstes Argument verkettet ist , und rufen sie dann aus dem Rückrufparameter ab (einem Array von Direktiven, die diesem Namen entsprechen).

Sobald wir es erhalten haben, können wir sein Bereichsobjekt erhalten und es nach Bedarf erweitern. Beachten Sie, dass dies alles im configBlock erfolgen muss.

Einige Notizen

  • Es wurde vorgeschlagen, einfach eine Direktive mit demselben Namen hinzuzufügen und dann ihre Prioritätsstufe festzulegen. Abgesehen davon, dass es unsemantisch ist (was nicht einmal ein Wort ist , weiß ich ...), wirft es Probleme auf, z. B. was ist, wenn sich die Prioritätsstufe der Richtlinie eines Drittanbieters ändert?

  • JeetendraChauhan hat behauptet (ich habe es jedoch nicht getestet), dass diese Lösung in Version 1.13 nicht funktioniert.

Eliran Malka
quelle
1
Ich schlage vor, Sie versuchen es mit der Antwort von @ sh0ber (erstellen Sie eine weitere Direktive, nur um Ereignisse auszusenden).
Eliran Malka
2
Ein kurzer Hinweis zu dieser Antwort (die hervorragend funktioniert), die 'Direktive' in 'paneDirective' hat einen Zweck ;-) Es hat eine Weile gedauert , bis ich das herausgefunden habe: stackoverflow.com/questions/19409017/… , siehe die akzeptierten Antworten.
Roy Milder
2
hi @EliranMalka check my plunker plnkr.co/edit/0mvQjHYjQCFS6joYJdwK hoffe, das wird jemandem helfen
Jeetendra Chauhan
1
Der Link zu decorator()ist defekt (aktualisiert auf docs.angularjs.org/api/auto/service/$provide#decorator )
Chris Brown
1
@EliranMalka ja, bindToControllerwurde in v1.3 eingeführt. Beachten Sie jedoch, dass dies keine alternative Lösung ist, sondern nur für einen bestimmten Fall, in dem die ursprüngliche Richtlinie mit der bindToControllerEigenschaft eingerichtet wurde. Gute Idee, ich werde dies als Antwort
posten
8

Obwohl dies nicht die direkte Antwort auf Ihre Frage ist, möchten Sie vielleicht wissen, dass die neueste Version (im Master) von http://angular-ui.github.io/bootstrap/ Unterstützung für das Deaktivieren von Registerkarten hinzugefügt hat. Diese Funktion wurde hinzugefügt über: https://github.com/angular-ui/bootstrap/commit/2b78dd16abd7e09846fa484331b5c35ece6619a2

pkozlowski.opensource
quelle
+1 für die Heads Up. gut zu wissen. Ich denke, Bowers Angular-Bootstrap und die Bootstrap-Komponente von Angular-UI sind nicht synchron.
Kyle
6

Eine andere Lösung, bei der Sie eine neue Direktive erstellen, die sie erweitert, ohne die ursprüngliche Direktive zu ändern

Die Lösung ähnelt der Dekorationslösung:

Erstellen Sie eine neue Direktive und fügen Sie als Abhängigkeit die Direktive ein, die Sie erweitern möchten

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

Auf diese Weise können Sie die ursprüngliche Direktive und die erweiterte Version in derselben App verwenden

Kidroca
quelle
2
Das ist großartig, genau das, was ich brauchte, um eine Direktive für den isolierten Bereich um meine eigenen Variablen zu erweitern !! Ich habe festgestellt, dass angle.extend keine Objekte tief kopiert, daher wird das Bereichsobjekt von paneDirective durch dieses ersetzt. Eine Alternative ist angle.merge, bei der der ursprüngliche Bereich von PaneDirective beibehalten und die hier definierten Variablen hinzugefügt / zusammengeführt werden.
Mathewguest
1
Ja, angular.mergehätte verwendet werden sollen, ich werde das Beispiel aktualisieren
Kidroca
1

Hier ist eine andere Lösung für ein anderes Szenario zum Erweitern von Bindungen auf eine Direktive mit dembindToController Eigenschaft.

Hinweis: Dies ist keine Alternative zu anderen hier angebotenen Lösungen. Es wird nur ein bestimmter Fall gelöst (der in anderen Antworten nicht behandelt wird), mit dem die ursprüngliche Richtlinie erstellt wurde bindToController.

Gilad Mayani
quelle