Welche “Dinge” können in Angular.js in andere injiziert werden?

Mir fällt es etwas schwer, Dependency Injection in Angular zu verstehen. Also meine Frage ist, kann jemand erklären, welche der “Typen”, wie Controller, Fabrik, Provider, etc. können wir in andere injizieren, einschließlich anderer Instanzen der gleichen “Typ”?

Was ich eigentlich suche, ist diese Tabelle, die mit y / n gefüllt ist. Bei Zellen mit derselben Zeile / Spalte bedeutet dies, dass der Wert eines “Typs” in einen anderen “gleichen” Typs mit demselben “Typ” injiziert wird.

+----------------+----------+------------+-----------+---------+--------+----------+---------+-------+ | Can we inject? | Constant | Controller | Directive | Factory | Filter | Provider | Service | Value | +----------------+----------+------------+-----------+---------+--------+----------+---------+-------+ | Constant | | | | | | | | | | Controller | | | | | | | | | | Directive | | | | | | | | | | Factory | | | | | | | | | | Filter | | | | | | | | | | Provider | | | | | | | | | | Service | | | | | | | | | | Value | | | | | | | | | +----------------+----------+------------+-----------+---------+--------+----------+---------+-------+ 

Anstatt nur die Tabelle mit “Ja” und “Nein” ohne Erklärung zu füllen, gehe ich ein bisschen mehr ins Detail.

[Hinweis, nach dem Abschluss hinzugefügt: das endete damit, dass … etwas länger als ich erwartet hatte. Es ist ein Tl; dr am Boden, aber ich hoffe, das ist informativ.]

[Diese Antwort wurde auch dem AngularJS-Wiki hinzugefügt: Verständnis der Dependenz-Injektion ]


Der Provider ( $provide )

Der $provide ist dafür verantwortlich, Angular mitzuteilen, wie neue injizierbare Dinge erstellt werden können; Diese Dinge nennt man Dienste . Dienste werden durch Dinge definiert, die als Provider bezeichnet werden. Dies ist das, was Sie erstellen, wenn Sie $provide . Die Definition eines Providers erfolgt über die provider Methode des $provide Service, und Sie können den $provide Service anfordern, indem Sie ihn in die config einer Anwendung config . Ein Beispiel könnte in etwa so aussehen:

 app.config(function($provide) { $provide.provider('greeting', function() { this.$get = function() { return function(name) { alert("Hello, " + name); }; }; }); }); 

Hier haben wir einen neuen Anbieter für einen Dienst namens greeting . Wir können eine Variable namens greeting in jede injizierbare function einfügen (wie Controller, mehr dazu später), und Angular wird die $get function des Providers aufrufen, um eine neue Instanz des Service zurückzugeben. In diesem Fall ist das Ding, das injiziert wird, eine function, die einen name und eine alert basierend auf dem Namen übernimmt. Wir könnten es so verwenden:

 app.controller('MainController', function($scope, greeting) { $scope.onClick = function() { greeting('Ford Prefect'); }; }); 

Jetzt ist hier der Trick. factory , service und value sind alles nur Abkürzungen, um verschiedene Teile eines Anbieters zu definieren – das heißt, sie bieten eine Möglichkeit, einen Anbieter zu definieren, ohne all diese Dinge eingeben zu müssen. Zum Beispiel könnten Sie den gleichen Anbieter genau so schreiben:

 app.config(function($provide) { $provide.factory('greeting', function() { return function(name) { alert("Hello, " + name); }; }); }); 

Es ist wichtig zu verstehen, also werde ich umformulieren: unter der Haube ruft AngularJS genau den gleichen Code auf , den wir oben geschrieben haben (die $provide.provider Version) für uns. Es gibt buchstäblich, 100% keinen Unterschied in den beiden Versionen. value funktioniert genauso – wenn alles, was wir von unserer $get function (auch factory function genannt) zurückgeben, immer genau gleich ist, können wir mit value noch weniger Code schreiben. Zum Beispiel, da wir immer die gleiche function für unseren greeting zurückgeben, können wir auch value , um es zu definieren:

 app.config(function($provide) { $provide.value('greeting', function(name) { alert("Hello, " + name); }); }); 

Auch dies ist zu 100% identisch mit den anderen beiden Methoden, die wir zur Definition dieser function verwendet haben – es ist nur eine Möglichkeit, etwas Tipparbeit zu sparen.

Jetzt haben Sie wahrscheinlich diese lästige app.config(function($provide) { ... }) , die ich verwendet habe, bemerkt. Da die Definition neuer Anbieter (über eine der oben genannten Methoden) so üblich ist, macht AngularJS die $provider Methoden direkt auf dem Modul-Objekt verfügbar, um noch mehr Tipparbeit zu sparen:

 var myMod = angular.module('myModule', []); myMod.provider("greeting", ...); myMod.factory("greeting", ...); myMod.value("greeting", ...); 

Diese alle machen dasselbe wie die ausführlicheren app.config(...) Versionen, die wir vorher benutzt haben.

Dasjenige, das ich bisher gespritzt habe, ist constant . Fürs Erste ist es einfach genug zu sagen, dass es genau wie value funktioniert. Wir werden sehen, dass es später einen Unterschied gibt.

Um zu überprüfen , machen alle diese Teile des Codes genau dasselbe:

 myMod.provider('greeting', function() { this.$get = function() { return function(name) { alert("Hello, " + name); }; }; }); myMod.factory('greeting', function() { return function(name) { alert("Hello, " + name); }; }); myMod.value('greeting', function(name) { alert("Hello, " + name); }); 

Der Injektor ( $injector )

Der Injektor ist verantwortlich für das Erstellen von Instanzen unserer Dienste unter Verwendung des Codes, den wir über $provide (kein Wortspiel beabsichtigt). Jedes Mal, wenn Sie eine function schreiben, die injizierte Argumente benötigt, sehen Sie den Injektor bei der Arbeit. Jede AngularJS-Anwendung verfügt über einen einzelnen $injector , der beim Start der Anwendung erstellt wird. Sie können es erreichen, indem Sie $injector in jede injizierbare function injizieren (ja, $injector weiß, wie man sich selbst injiziert!)

Sobald Sie $injector , können Sie eine Instanz eines definierten Dienstes abrufen get indem Sie get mit dem Namen des Dienstes aufrufen. Beispielsweise,

 var greeting = $injector.get('greeting'); greeting('Ford Prefect'); 

Der Injektor ist auch dafür verantwortlich, Dienste in functionen zu injizieren; Zum Beispiel können Sie Dienste in jede function injizieren, die Sie verwenden, indem Sie die Injector-Methode des Injektors verwenden.

 var myFunction = function(greeting) { greeting('Ford Prefect'); }; $injector.invoke(myFunction); 

Es ist erwähnenswert, dass der Injektor nur einmal eine Instanz eines Dienstes erstellt. Es speichert dann, was auch immer der Anbieter durch den Namen des Dienstes zurückgibt; das nächste Mal, wenn Sie nach dem Service fragen, erhalten Sie tatsächlich genau das gleiche Objekt.

Um also Ihre Frage zu beantworten, können Sie Dienste in jede function einfügen , die mit $injector.invoke aufgerufen wird . Das beinhaltet

  • Controller-Definitionsfunktionen
  • Direktive Definition functionen
  • Filterdefinitionsfunktionen
  • die $get Methoden von Providern (auch die factory Definition-functionen genannt)

Da constant s und value s immer einen statischen Wert zurückgeben, werden sie nicht über den Injektor aufgerufen und können daher nicht mit etwas injiziert werden.

Provider konfigurieren

Sie wundern sich vielleicht, warum irgendjemand sich die Mühe machen würde, einen vollwertigen Anbieter mit der provide zu gründen, wenn factory , value usw. so viel einfacher sind. Die Antwort ist, dass Provider viel Konfiguration erlauben. Wir haben bereits erwähnt, dass Sie beim Erstellen eines Dienstes über den Anbieter (oder eine der Abkürzungen, die Ihnen Angular zur Verfügung stellt) einen neuen Anbieter erstellen, der definiert, wie dieser Dienst aufgebaut wird. Was ich nicht erwähnt habe, ist, dass diese Anbieter in die config Ihrer Anwendung config werden können, damit Sie mit ihnen interagieren können!

Zunächst führt Angular Ihre Anwendung in zwei Phasen durch – die config und die run . In der config , wie wir gesehen haben, beliebige Anbieter einrichten. Hier werden auch Direktiven, Controller, Filter und Ähnliches eingerichtet. In der run Phase kompiliert Angular tatsächlich Ihr DOM und startet Ihre App.

Mit den functionen myMod.config und myMod.run können Sie zusätzlichen Code hinzufügen, der in diesen Phasen ausgeführt wird. myMod.config myMod.run eine function, die während dieser Phase ausgeführt wird. Wie wir im ersten Abschnitt gesehen haben, sind diese functionen injizierbar – wir injizierten den integrierten $provide Service in unser erstes Codebeispiel. Bemerkenswert ist jedoch, dass während der config Phase nur Provider injiziert werden können (mit Ausnahme der Dienste im AUTO Modul – $provide und $injector injector).

Zum Beispiel ist Folgendes nicht erlaubt :

 myMod.config(function(greeting) { // WON'T WORK -- greeting is an *instance* of a service. // Only providers for services can be injected in config blocks. }); 

Was Sie haben, sind Anbieter für Dienste, die Sie getätigt haben:

 myMod.config(function(greetingProvider) { // a-ok! }); 

Es gibt eine wichtige Ausnahme: constant s, da sie nicht geändert werden können, dürfen innerhalb von config injiziert werden (so unterscheiden sie sich vom value s). Sie sind nur mit ihrem Namen erreichbar (kein Provider Suffix notwendig).

Wenn Sie einen Anbieter für einen Dienst definiert haben, erhält dieser Anbieter den Namen serviceProvider , wobei service der Name des Dienstes ist. Jetzt können wir die Macht der Provider nutzen, um etwas komplizierteres zu tun!

 myMod.provider('greeting', function() { var text = 'Hello, '; this.setText = function(value) { text = value; }; this.$get = function() { return function(name) { alert(text + name); }; }; }); myMod.config(function(greetingProvider) { greetingProvider.setText("Howdy there, "); }); myMod.run(function(greeting) { greeting('Ford Prefect'); }); 

Jetzt haben wir eine function namens setText bei unserem Provider, mit der wir unseren alert anpassen können. Wir können in einem config Block auf diesen Provider zugreifen, um diese Methode aufzurufen und den Service anzupassen. Wenn wir unsere App endlich ausführen, können wir den greeting und ausprobieren, ob unsere Anpassung wirksam wird.

Da dies ein komplexeres Beispiel ist, hier eine funktionierende Demonstration: http://jsfiddle.net/BinaryMuse/9GjYg/

Controller ( $controller )

Controller-functionen können injiziert werden, aber Controller selbst können nicht in andere Dinge injiziert werden. Das liegt daran, dass Controller nicht über den Provider erstellt werden. Stattdessen gibt es einen integrierten Angular-Dienst namens $controller , der für die Einrichtung Ihrer Controller zuständig ist. Wenn Sie myMod.controller(...) aufrufen, myMod.controller(...) Sie genau wie im letzten Abschnitt auf den Provider dieses Dienstes zu .

Zum Beispiel, wenn Sie einen Controller wie folgt definieren:

 myMod.controller('MainController', function($scope) { // ... }); 

Was Sie eigentlich machen, ist folgendes:

 myMod.config(function($controllerProvider) { $controllerProvider.register('MainController', function($scope) { // ... }); }); 

Später, wenn Angular eine Instanz Ihres Controllers erstellen muss, verwendet es den $controller Dienst (der wiederum den $injector , um die Controller-function aufzurufen, so dass auch die Abhängigkeiten in ihm injiziert werden).

Filter und Richtlinien

filter und directive arbeiten genauso wie controller ; filter verwendet einen Service namens $filter und dessen Provider $filterProvider , während die directive einen Service namens $compile und dessen Provider $compileProvider . Einige Links:

Wie in den anderen Beispielen sind myMod.filter und myMod.directive Verknüpfungen zum Konfigurieren dieser Dienste.


tl; dr

Zusammenfassend kann jede function, die mit $injector.invoke aufgerufen wird , injiziert werden . Dies beinhaltet, von Ihrem Diagramm (ist aber nicht beschränkt auf):

  • Regler
  • Richtlinie
  • Fabrik
  • Filter
  • provider $get (beim Definieren des Providers als Objekt)
  • Provider-function (bei Definition des Providers als Konstruktorfunktion)
  • Bedienung

Der Anbieter erstellt neue Dienste , die in Dinge eingefügt werden können . Das beinhaltet:

  • Konstante
  • Fabrik
  • Anbieter
  • Bedienung
  • Wert

Das heißt, integrierte Dienste wie $controller und $filter können eingefügt werden, und Sie können diese Dienste verwenden, um die neuen Filter und Controller zu erhalten, die Sie mit diesen Methoden definiert haben (obwohl die Dinge, die Sie definiert haben, nicht für sich alleine sind) , in der Lage, in Dinge injiziert zu werden).

Darüber hinaus kann jede in Injektor aufgerufene function mit einem beliebigen vom Provider bereitgestellten Dienst injiziert werden – es gibt keine Einschränkung ( config hier aufgeführten config und run ).

Der Punkt, den BinaryMuse in ihrer erstaunlichen Antwort über Anbieter, Fabriken und Dienstleistungen macht, ist alles sehr wichtig.

Unten ist ein Bild, von dem ich denke, dass es ihren Standpunkt visuell veranschaulichen kann:

AngularJS sind alle nur Anbieter http://www.simplygoodcode.com/wp-content/uploads/2015/11/angularjs-provider-service-factory-highlight.png

Große Antwort von Michelle. Ich möchte nur darauf hinweisen, dass Direktiven eingegeben werden können. Wenn Sie eine Direktive namens myThing , können Sie sie mit myThingDirective injizieren: Hier ist ein künstliches Beispiel .

Das obige Beispiel ist nicht sehr praktisch, aber die Möglichkeit, eine Direktive zu injizieren, ist nützlich, wenn Sie diese Direktive dekorieren wollen.