повторно открыть и добавить зависимости к уже загруженному приложению

89

Есть ли способ внедрить позднюю зависимость в уже загруженный модуль angular? Вот что я имею в виду:

Скажем, у меня есть угловое приложение для всего сайта, определенное как:

// in app.js
var App = angular.module("App", []);

И на каждой странице:

<html ng-app="App">

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

// in reports.js
var App = angular.module("App")
App.controller("ReportsController", ['$scope', function($scope) {
  // .. reports controller code
}])

Теперь, говорят , что один из этих битов по требованию логики также требует их собственных зависимостей (например ngTouch, ngAnimate, ngResourceи т.д.). Как я могу прикрепить их к базовому приложению? Кажется, это не работает:

// in reports.js
var App = angular.module("App", ['ui.event', 'ngResource']); // <-- raise error when App was already bootstrapped

Я понимаю, что все могу сделать заранее, т.е.

// in app.js
var App = angular.module("App", ['ui.event', 'ngResource', 'ngAnimate', ...]);

Или определите каждый модуль отдельно, а затем вставьте все в основное приложение ( подробнее см. Здесь ):

// in reports.js
angular.module("Reports", ['ui.event', 'ngResource'])
.controller("ReportsController", ['$scope', function($scope) {
  // .. reports controller code
}])

// in home.js
angular.module("Home", ['ngAnimate'])
.controller("HomeController", ['$scope', '$http', function($scope, $http){
  // ...
}])

// in app.js, loaded last into the page (different for every page that varies in dependencies)
var App = angular.module("App", ['Reports', 'Home'])

Но это потребует, чтобы я каждый раз инициализировал приложение с зависимостями текущей страницы.

Я предпочитаю включать базовый код app.jsна каждую страницу и просто вводить необходимые расширения на каждую страницу ( reports.js, home.jsи т. Д.), Без необходимости пересматривать логику начальной загрузки каждый раз, когда я что-то добавляю или удаляю.

Есть ли способ ввести зависимости, когда приложение уже загружено? Что считается идиоматическим способом (или способами) сделать это? Я склоняюсь к последнему решению, но хотел посмотреть, можно ли сделать то, что я описал. Спасибо.

sa125
источник
Не могли бы вы дать мне ваш последний рабочий код, чтобы взглянуть на него?
Мангу Сингх Раджпурохит
@ user2393267 ммм, так давно, понятия не имею, есть ли у меня этот код ... Извините. Я думаю, что в конце концов я пересмотрел дизайн, потому что обычно, когда мне приходится что-то взламывать, это означает, что я делаю это неправильно ... Однако, если вы все еще полны решимости придерживаться этого подхода, ответ ниже кажется хорошим заделом .
sa125,

Ответы:

115

Я решил это так:

снова обратитесь к приложению:

var app = angular.module('app');

затем поместите свои новые требования в массив требований:

app.requires.push('newDependency');
АльБараа Ш
источник
3
Это работает для меня +1. Я использовал это для нескольких зависимостей, например app.requires.push ('doctorCtrl', 'doctorService');
Amir
8
Это спасло мою архитектуру.
Саид Нямати,
3
У меня это не работает. Я добавляю зависимость динамически, как описано, но Angular по-прежнему не может найти службу в добавленном модуле.
Слава Фомин II
6
И app.requiresявляется массивом, поэтому, если вы добавляете несколько зависимостей (как в примере с отчетами), вы передаете их как отдельные аргументы pushметоду: app.requires.push('ui.event', 'ngResource');или, если ваши дополнительные зависимости уже являются массивом:Array.prototype.push.apply(app.requires, ['ui.event', 'ngResource'])
Red Pea,
2
Иногда я пропускаю голосование, потому что не хочу входить в систему, не в этот раз! Благодарность!
CularBytes
12

Просто ... Получите экземпляр модуля с помощью геттера следующим образом: var app = angular.module ("App");

Затем добавьте в коллекцию «требуется», например: app.requires [app.requires.length] = «ngResource»;

Во всяком случае, у меня это сработало. УДАЧИ!

Дэвид Донован
источник
4
Это сработало для меня! У меня вопрос - почему бы не использовать: app.requires.push ("ngResource")?
Филипп Мунин,
9

Согласно этому предложению в группе Google Angular JS эта функциональность на данный момент не существует. Надеюсь, основная команда решит добавить эту функциональность и сможет использовать ее сама.

Мэтт Нибеккер
источник
4
Да, это кажется особенно полезным для людей, которые не обязательно хотят строить SPA.
regularmike 03
4

Если вы хотите добавить сразу несколько зависимостей, вы можете передать их в push следующим образом:

<script>
    var app = angular.module('appName');
    app.requires.push('dependencyCtrl1', 'dependencyService1');
</script>
Амир
источник
4

Я понимаю, что это старый вопрос, однако рабочего ответа пока нет, поэтому я решил рассказать, как я его решил.

Решение требует разветвления Angular, поэтому вы больше не можете использовать CDN. Однако модификация очень небольшая, поэтому я удивлен, почему этой функции нет в Angular.

Я перешел по ссылке на группы Google, которая была предоставлена ​​в одном из других ответов на этот вопрос. Там я нашел следующий код, который решил проблему:

instanceInjector.loadNewModules = function (mods) {
  forEach(loadModules(mods), function(fn) { instanceInjector.invoke(fn || noop); });
};

Когда я добавил этот код в строку 4414 исходного кода angular 1.5.0 (внутри createInjectorфункции, перед return instanceInjector;оператором), это позволило мне добавить зависимости после такой начальной загрузки $injector.loadNewModules(['ngCookies']);.

Tjespe
источник
? Что не так с ответом, получившим наибольшее количество голосов (по состоянию на 26.06.2017) ? Похоже, он был предоставлен более чем за год до того, как вы разместили это; у вашего ответа есть преимущество?
The Red Pea
@TheRedPea Ну, в этом нет ничего плохого, за исключением того, что он не решил мою проблему, но этот ответ
помог
И это не сработало для вас, потому что, я полагаю, вы уже загрузили свое приложение? Я тоже это заметил ...
Красный горошек
2
Прочитав ссылку на публикацию в сообществе Google, я еще больше уверен, что именно благодаря начальной загрузке такое решение необходимо. Голосование за то, что исходный вопрос был задан об «уже загруженном приложении», к которому никто больше не обращается (на самом деле OP, возможно, высказался неправильно)
Red Pea
1

Начиная с версии 1.6.7 появилась возможность ленивой загрузки модулей после загрузки приложения с использованием $injector.loadNewModules([modules]). Ниже приведен пример из документации AngularJS:

app.factory('loadModule', function($injector) {
   return function loadModule(moduleName, bundleUrl) {
     return getScript(bundleUrl).then(function() { $injector.loadNewModules([moduleName]); });
   };
})

Пожалуйста, прочтите полную документацию о loadNewModules, так как здесь есть некоторые подводные камни.

Также есть очень хороший пример приложения от omkadiri, использующий его с ui-router.

Денис Пшенов
источник