Quelles «choses» peuvent être injectées dans d’autres dans Angular.js?

J’ai un peu de mal à comprendre l’dependency injection en angular. Donc, ma question est la suivante: quelqu’un peut-il expliquer lequel des types, comme Controller, Factory, Provider, etc., peut être injecté dans d’autres, y compris d’autres instances du même “type”?

Ce que je cherche réellement, c’est cette table remplie de y / n. Pour les cellules avec la même ligne / colonne, cela signifie que la valeur d’un “type” est injectée dans une autre avec le même “type”

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

Plutôt que de simplement remplir le tableau avec “oui” et “non” sans aucune explication, je vais entrer dans un peu plus de détails.

[Note, ajouté après avoir fini: cela a fini par être … un peu plus long que prévu. Il y a un tl; dr en bas, mais j’espère que cela s’avère informatif.]

[Cette réponse a également été ajoutée au wiki AngularJS: Comprendre la dépendance par injection ]


Le fournisseur ( $provide )

Le service $provide est chargé de dire à Angular comment créer de nouvelles substances injectables; ces choses sont appelées services . Les services sont définis par des éléments appelés fournisseurs , ce que vous créez lorsque vous utilisez $provide . La définition d’un fournisseur se fait via la méthode provider du service $provide et vous pouvez obtenir le service $provide en lui demandant de l’injecter dans la fonction de config application. Un exemple pourrait être quelque chose comme ceci:

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

Nous avons défini ici un nouveau fournisseur pour un service appelé greeting . nous pouvons injecter une variable nommée greeting dans n’importe quelle fonction injectable (comme les contrôleurs, plus tard) et Angular appellera la fonction $get du fournisseur afin de renvoyer une nouvelle instance du service. Dans ce cas, la chose qui sera injectée est une fonction qui prend un paramètre name et alert message en fonction du nom. Nous pourrions l’utiliser comme ceci:

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

Maintenant, voici le truc. factory , le service et la value sont que des raccourcis pour définir différentes parties d’un fournisseur, c’est-à-dire qu’ils permettent de définir un fournisseur sans avoir à taper tous ces éléments. Par exemple, vous pouvez écrire exactement le même fournisseur comme ceci:

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

Il est important de comprendre, alors je vais reformuler: sous le capot, AngularJS appelle exactement le même code que celui que nous avons écrit ci-dessus (la version $provide.provider ) pour nous. Il y a littéralement, 100% aucune différence dans les deux versions. value fonctionne de la même manière – si tout ce que nous retournerions de notre fonction $get (notre fonction factory ) est toujours identique, nous pouvons écrire encore moins de code en utilisant la value . Par exemple, comme nous retournons toujours la même fonction pour notre service d’ greeting , nous pouvons également utiliser value pour le définir:

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

Encore une fois, ceci est 100% identique aux deux autres méthodes que nous avons utilisées pour définir cette fonction – c’est juste un moyen d’économiser de la saisie.

Maintenant, vous avez probablement remarqué cette app.config(function($provide) { ... }) ennuyeuse que j’ai utilisée. Étant donné que la définition de nouveaux fournisseurs (via l’ une des méthodes ci-dessus) est si courante, AngularJS expose directement les méthodes $provider sur l’object du module, afin d’économiser encore plus de saisie:

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

Celles-ci font la même chose que les versions plus verbeuses app.config(...) nous app.config(...) précédemment.

Le seul injectable que j’ai sauté jusqu’ici est constant . Pour le moment, il est assez facile de dire que cela fonctionne comme de la value . Nous verrons qu’il y a une différence plus tard.

Pour passer en revue , tous ces morceaux de code font exactement la même chose:

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

L’injecteur ( $injector )

L’injecteur est responsable de la création des instances de nos services en utilisant le code que nous avons fourni via $provide (sans jeu de mots). Chaque fois que vous écrivez une fonction qui prend des arguments injectés, vous voyez l’injecteur au travail. Chaque application AngularJS possède un seul $injector qui est créé lors du premier démarrage de l’application. vous pouvez vous en procurer en injectant $injector dans n’importe quelle fonction injectable (oui, $injector sait s’injecter!)

Une fois que vous avez $injector , vous pouvez obtenir une instance d’un service défini en appelant get avec le nom du service. Par exemple,

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

L’injecteur est également chargé d’injecter des services dans les fonctions; Par exemple, vous pouvez injecter par magie des services dans n’importe quelle fonction à l’aide de la méthode d’ invoke l’injecteur;

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

Il convient de noter que l’injecteur ne créera qu’une instance d’un service une fois . Il met ensuite en cache tout ce que le fournisseur renvoie par le nom du service; La prochaine fois que vous demanderez le service, vous obtiendrez exactement le même object.

Donc, pour répondre à votre question, vous pouvez injecter des services dans toute fonction appelée avec $injector.invoke . Ceci comprend

  • fonctions de définition du contrôleur
  • fonctions de définition de directive
  • fonctions de définition de filtre
  • les méthodes $get des fournisseurs (alias les fonctions de définition d’ factory )

Puisque les constant s et la value s renvoient toujours une valeur statique, elles ne sont pas appelées via l’injecteur et vous ne pouvez donc rien leur injecter.

Configuration des fournisseurs

Vous vous demandez peut-être pourquoi quelqu’un voudrait mettre en place un fournisseur à part entière avec la méthode provision si l’ factory , la value , etc. sont beaucoup plus faciles. La réponse est que les fournisseurs permettent beaucoup de configuration. Nous avons déjà mentionné que lorsque vous créez un service via le fournisseur (ou tout raccourci que Angular vous fournit), vous créez un nouveau fournisseur qui définit la manière dont ce service est construit. Ce que je n’ai pas mentionné, c’est que ces fournisseurs peuvent être injectés dans les sections de config de votre application afin que vous puissiez interagir avec eux!

Tout d’abord, Angular exécute votre application en deux phases – les phases de config et d’ run . La phase de config , comme nous l’avons vu, est l’endroit où vous pouvez configurer des fournisseurs si nécessaire. C’est aussi là que les directives, les contrôleurs, les filtres et autres sont configurés. La phase d’ run , comme vous pouvez le deviner, est l’endroit où Angular comstack réellement votre DOM et démarre votre application.

Vous pouvez append du code supplémentaire à exécuter dans ces phases avec les fonctions myMod.config et myMod.run – chacune d’entre elles myMod.run une fonction pendant cette phase spécifique. Comme nous l’avons vu dans la première section, ces fonctions sont injectables – nous avons injecté le service $provide provision intégré dans notre tout premier exemple de code. Cependant, ce qui est intéressant à noter, c’est que pendant la phase de config , seuls les fournisseurs peuvent être injectés (à l’exception des services du module AUTO : $provide et $injector injector).

Par exemple, les éléments suivants ne sont pas autorisés :

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

Vous avez access à des fournisseurs de services que vous avez créés:

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

Il existe une exception importante: les constant , car elles ne peuvent pas être modifiées, peuvent être injectées dans des blocs de config (elles diffèrent ainsi des value s). Ils sont accédés par leur nom seul (pas de suffixe Provider nécessaire).

Chaque fois que vous avez défini un fournisseur pour un service, ce fournisseur s’appelle serviceProvider , où service est le nom du service. Maintenant, nous pouvons utiliser le pouvoir des fournisseurs faire des choses plus compliquées!

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

Maintenant, nous avons une fonction sur notre fournisseur appelée setText que nous pouvons utiliser pour personnaliser notre alert ; nous pouvons avoir access à ce fournisseur dans un bloc de config pour appeler cette méthode et personnaliser le service. Lorsque nous exécutons enfin notre application, nous pouvons récupérer le service de messagerie et l’essayer pour vérifier que notre personnalisation est effective.

Comme il s’agit d’un exemple plus complexe, voici une démonstration pratique: http://jsfiddle.net/BinaryMuse/9GjYg/

Contrôleurs (contrôleur $controller )

Les fonctions du contrôleur peuvent être injectées, mais les contrôleurs eux-mêmes ne peuvent pas être injectés dans d’autres choses. C’est parce que les contrôleurs ne sont pas créés via le fournisseur. Au lieu de cela, il existe un service Angular $controller appelé $controller qui est responsable de la configuration de vos contrôleurs. Lorsque vous appelez myMod.controller(...) , vous accédez en fait au fournisseur de ce service , comme dans la dernière section.

Par exemple, lorsque vous définissez un contrôleur comme celui-ci:

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

Ce que vous faites en réalité, c’est ceci:

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

Plus tard, lorsque Angular a besoin de créer une instance de votre contrôleur, il utilise le service $controller (qui utilise à son tour l’ $injector pour appeler votre fonction de contrôleur afin qu’il injecte également ses dépendances).

Filtres et directives

filter et la directive fonctionnent exactement de la même manière que le controller ; filter utilise un service appelé $filter et son fournisseur $filterProvider , tandis que directive utilise un service appelé $comstack et son fournisseur $comstackProvider . Quelques liens:

Conformément aux autres exemples, myMod.filter et myMod.directive sont des raccourcis pour configurer ces services.


tl; dr

Donc, pour résumer, toute fonction appelée avec $injector.invoke peut être injectée dans . Cela inclut, à partir de votre graphique (mais ne se limite pas à):

  • manette
  • directif
  • usine
  • filtre
  • provider $get (lors de la définition du fournisseur en tant qu’object)
  • fonction fournisseur (lors de la définition du fournisseur en tant que fonction constructeur)
  • un service

Le fournisseur crée de nouveaux services pouvant être injectés dans les choses . Ceci comprend:

  • constant
  • usine
  • fournisseur
  • un service
  • valeur

Cela dit, les services intégrés comme $controller et $filter peuvent être injectés, et vous pouvez utiliser ces services pour obtenir les nouveaux filtres et contrôleurs que vous avez définis avec ces méthodes (même si les choses que vous avez définies ne sont pas, à elles seules, , capable d’être injecté dans les choses).

En dehors de cela, toute fonction invoquée par un injecteur peut être injectée avec n’importe quel service fourni par le fournisseur – il n’y a pas de ressortingction (autre que les différences de config et d’ run listées ici).

Le point que BinaryMuse apporte dans sa réponse étonnante sur les fournisseurs, les usines et les services est extrêmement important.

Voici une image qui, à mon avis, peut illustrer visuellement son propos:

AngularJS ils sont tous des fournisseurs justes http://www.simplygoodcode.com/wp-content/uploads/2015/11/angularjs-provider-service-factory-highlight.png

Bonne réponse de Michelle. Je veux juste souligner que les directives peuvent être injectées. Si vous avez une directive nommée myThing , vous pouvez l’injecter avec myThingDirective : Voici un exemple artificiel .

L’exemple ci-dessus n’est pas très pratique, mais la possibilité d’injecter une directive est utile lorsque vous souhaitez décorer cette directive .