53 votes

Ne peut pas récupérer l'injecteur à partir d'angular

J'ai cette application avec deux modules :

angular.module('components', []).directive('foo', function () { return {};});
angular.module('gaad', ['components']);

Il y a un tas de directives associées à ces modules que je n'inclus pas ici. L'application fonctionne bien. Cependant, lorsque j'essaie de récupérer l'injecteur du module gaad :

var injector = angular.injector(['gaad', 'components']); // appelé après l'initialisation du module 'gaad'

l'erreur est lancée :

Uncaught Error: Unknown provider: $compileProvider from components 

L'application est assez grande maintenant et je n'ai pas d'idée où chercher les bugs. Donc ma question est : Quelle pourrait être la raison de mes problèmes ?

EDIT : J'ai pu reproduire mon problème: http://jsfiddle.net/selbh/ehmnt/11/

121voto

pkozlowski.opensource Points 52557

Avant de répondre à la question, nous devons noter qu'il n'y a qu'une seule instance d'injecteur par application et non par module. En ce sens, il n'est pas possible de récupérer un injecteur par module. Bien sûr, si nous prenons le module de niveau supérieur, il représente l'ensemble de l'application. En ce sens, une application et un module de niveau supérieur semblent équivalents. Cela peut sembler être une différence subtile mais il est important de comprendre cela afin de répondre pleinement et correctement à cette question.

Ensuite, de ce que je peux comprendre, vous aimeriez récupérer le $injecteur et non en créer une nouvelle instance. Le fait est que le angular.injector créera une nouvelle instance de $injecteur pour les modules (une application) spécifiés en tant qu'arguments. Ici, le principal module AngularJS (ng) doit être spécifié explicitement. Donc, dans cet exemple de code :

var injector = angular.injector(['gaad', 'components']);

vous essayiez de créer un nouvel injecteur à partir des composants définis dans les modules 'gaad' et 'composants' et évidemment $compileProvider n'est pas défini dans vos modules personnalisés. Ajouter le module ng à la liste "résoudrait" le problème en créant un nouvel injecteur - quelque chose que vous ne voulez probablement pas qu'il se produise.

Pour réellement récupérer une instance d'injecteur associée à une application en cours d'exécution nous pouvons utiliser 2 méthodes :

Voici le jsFiddle montrant 2 méthodes de récupération de l'injecteur : http://jsfiddle.net/xaQzb/

Veuillez également noter que l'utilisation de $injecteur directement n'est pas un scénario très courant en dehors des tests unitaires. Cela pourrait cependant être utile pour récupérer des services AngularJS en dehors du monde AngularJS. Plus d'informations ici : Appeler Angular JS à partir de code hérité.

13voto

Ryan O'Neill Points 2279

Il semble que vous devez inclure ng dans l'injecteur également.

var injector = angular.injector(['ng', 'b', 'a']);

À partir de : AngularJS: injector

Le module ng doit être ajouté explicitement.

2voto

tetotechy Points 121

Le problème se situe dans le flux d'exécution du code Angular. Pour compléter la réponse de @pkozlowski.opensource et les commentaires associés, notez que la propriété $injector est rendue disponible aux éléments du DOM après l'exécution du code du module, de sorte que lorsque vous accédez à la propriété (comme lorsque vous essayez de console.log), la propriété sera toujours undefined.

Vous pouvez résoudre ce problème en définissant simplement un délai de 0 millisecondes à l'exécution de la fonction de journalisation (c'est-à-dire, aucun délai explicite en millisecondes n'est nécessaire). Ce "hack" fonctionne car la fonction de journalisation sera exécutée lorsque la pile est vide, c'est-à-dire lorsque le processus de démarrage d'Angular a pris fin et que la propriété $injector est disponible pour les éléments du DOM.

Une autre (peut-être meilleure) solution dans le langage Angular serait d'inclure votre code d'accès au $injector dans un bloc run (voir aussi l'API associée). Le $injector pourrait alors être facilement injecté dans la fonction d'initialisation en tant que service normal. Cela fonctionne car les blocs run sont mis en file d'attente et exécutés de manière asynchrone une fois que tout le processus de démarrage est terminé.

Vous trouverez ci-dessous deux fiddles, un pour chaque solution.

0 Timeout jsFiddle

Run block jsFiddle

ÉDITER

De plus, il est généralement inutile de charger explicitement le module ng. Dans des cas normaux, le module ng est déjà automatiquement chargé, sauf si vous souhaitez effectuer un démarrage manuel du code Angular. Le fragment de documentation référencé dans l'une des réponses fait référence (implicitement, malheureusement) à la procédure de démarrage manuel d'Angular, lorsque vous devez créer manuellement l'injecteur et lui indiquer quels modules vous souhaitez charger.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X