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

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

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 

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

РЕДАКТИРОВАТЬ: я смог повторить мою проблему: http://jsfiddle.net/selbh/ehmnt/11/

3 ответа

Решение

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

Далее, насколько я понимаю, вы хотели бы получить $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 из старого кода.

Похоже, вам нужно включить нг в инжектор.

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

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

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

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

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

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

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

0 Тайм-аут jsFiddle

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

РЕДАКТИРОВАТЬ

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

Другие вопросы по тегам