Не удается извлечь инжектор из angular

У меня есть это приложение с двумя модулями:

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

Существует множество директив, связанных с этими модулями, которые я здесь не включаю. Приложение работает нормально. Однако когда я пытаюсь извлечь инжектор для модуля gaad:

var injector = angular.injector(['gaad', 'components']); //called after 'gaad' module initialization

выдается ошибка:

Uncaught Error: Unknown provider: $compileProvider from components 

Приложение довольно большое прямо сейчас, и я понятия не имею, где искать ошибки. Итак, мой вопрос: Что может быть причиной моих проблем?

EDIT: Я смог реплицировать свою проблему: http://jsfiddle.net/selbh/ehmnt/11/

Ответ 1

Прежде чем ответить на вопрос, мы должны отметить, что существует только один экземпляр инжектора для каждого приложения, а не для модуля. В этом смысле невозможно получить инжектор на модуль. Конечно, если мы возьмем модуль верхнего уровня, он будет представлять все приложение. В этом смысле приложение и модуль верхнего уровня кажутся эквивалентными. Это может показаться тонкой разницей, но важно понять, чтобы полностью и правильно ответить на этот вопрос.

Далее, из того, что я могу понять, вы хотели бы получить $injector, а не создать новый экземпляр. Дело в том, что angular.injector создаст новый экземпляр $injector для модулей (приложения), указанных в качестве аргументов. Здесь главный модуль AngularJS (ng) должен быть указан явно. Итак, в этом примере кода:

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

вы пытались создать новый инжектор из компонентов, определенных в модулях "gaad" и "components", и, очевидно, $compileProvider не определен в ваших настраиваемых модулях. Добавление модуля ng в список "решит" проблему, создав новый инжектор - что-то, чего вы, вероятно, не захотите.

Чтобы действительно получить экземпляр инжектора, связанный с запущенным приложением, мы можем использовать 2 метода:

  • из AngularJS JavaScript самое простое решение - просто ввести экземпляр $injector: http://docs.angularjs.org/api/angular.injector
  • извне мира AngularJS - вызов angular.element([DOM element]).injector(), где [элемент DOM] является элементом купола, где был определен ng-app (или любой дочерний элемент этого элемента). Подробнее здесь: http://docs.angularjs.org/api/angular.element

Вот jsFiddle, показывающий 2 метода извлечения инжектора: http://jsfiddle.net/xaQzb/

Также обратите внимание, что использование $injector напрямую не является очень распространенным сценарием вне модульного тестирования. Возможно, было бы полезно подумать о том, чтобы получить услуги AngularJS из-за пределов мира AngularJS. Подробнее здесь: Вызвать Angular JS из устаревшего кода.

Ответ 2

Кажется, вам нужно включить ng в инжектор.

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

От: AngularJS: инжектор

Модуль ng должен быть явно добавлен.

Ответ 3

Проблема заключается в потоке выполнения кода Angular. Чтобы интегрировать ответы @pkozlowski.opensource и соответствующие комментарии, обратите внимание, что свойство $injector становится доступным для элементов DOM после выполнения кода модуля, так что когда вы получаете доступ к свойству (как при попытке console.log его) свойство все равно будет undefined.

Вы можете решить эту проблему, просто установив 0 тайм-аут на выполнение функции ведения журнала (т.е. не требуется явная задержка в миллисекундах). Этот хак работает, потому что функция регистрации будет выполняться, когда стек пуст, то есть когда завершена перезагрузка Angular, и свойство $injector доступно для элементов DOM.

Другим (возможно, лучшим) решением в Angular lingo будет включение вашего $injector -ассингового кода в блок запуска (см. также связанный API). Затем $injector можно легко ввести в функцию инициализации как обычную службу. Это работает, потому что блоки запуска ставятся в очередь и выполняются асинхронно, когда завершается вся загрузка.

Ниже вы можете найти два скрипта, по одному для каждого решения.

0 Тайм-аут jsFiddle

Запустить блок jsFiddle

ИЗМЕНИТЬ

Кроме того, обычно нет необходимости явно загружать модуль ng. В обычных случаях модель ng уже загружена автоматически, если вы не хотите выполнять ручную загрузку кода Angular. Часть документов, на которые ссылается в одном из ответов, ссылается (неявно, к сожалению) на процедуру ручной загрузки w00 > , когда вам нужно вручную создать инжектор и сказать, какие модули вы хотите загрузить