Как вводить модули в основной модуль приложения Angular на лету

Я не использую angular для одностраничного приложения, но я хотел бы определить основной модуль приложения один раз из-за проблем с загрузкой. В то же время я хотел бы вводить/требовать модули на основе каждой страницы, а не одеяло, поскольку не все файлы JS будут загружены на каждую страницу.

Могу ли я определить приложение без необходимых модулей:

app = angular.module( "app", [])

и вводите ли они их из контроллера или на более поздней стадии?

Ответ 1

Нет, это официально не поддерживается на данный момент. Все модули должны быть загружены в браузер (и объявлены как зависимость основного модуля приложения) до того, как приложение AngularJS будет загружено.

Ответ 2

Сверху моей головы, прочитав свой вопрос, я могу думать о возможном решении/взломе.

Идея заключалась бы в определении массива зависимостей перед включением любых модулей и добавлении к ним в каждом модуле:

// before anything else
window.loadedDependencies = [];

// at the end of each module file:
window.loadedDependencies.push('moduleName')

// after all that, at the app definition:
app = angular.module("app", loadedDependencies)

Честно говоря, я действительно не рассматривал какие-либо последствия/осложнения, которые этот метод может подразумевать, и я не могу не ручаться за это до тех пор, пока не сделаю (почему не так много вызовов для файлов script и кеширования хороших для вашего случая использования?)

Ответ 3

Используя отличную идею Tiago (повышайте его!), в моем модуле есть следующее:

window.dependencies = _.union(window.dependencies || [], [
    "ngRoute",
    "app.mymodule1"
]);

angular
    .module("app.mymodule1", [])
    .config(["$routeProvider", function ($routeProvider) {
        // more code
    }]);

и это в моем app.js:

var app;

window.dependencies = _.union(window.dependencies || [], [
    "ngRoute",
    "app.anothermodule"
]);

window.app = app = angular.module("app", window.dependencies);

Я использую LoDash, поэтому я union зависимости для получения массива уникальных значений - некоторые из моих модулей используют те же зависимости, что и app.js, например ngRoute.

Мой script включает в себя нижнюю часть тега body, как показано ниже:

<!-- scripts from other pages/modules included here -->

<script src="/js/anothermodule/anothermodule.js"></script>
<script src="/js/app.js"></script>

Работает как шарм!

Мои страницы разделяют страницу "master", но у меня есть определения модулей в их собственных файлах, поэтому мне нужно что-то вроде этого.

Ответ 4

Мы можем достичь этого, используя app.requires

//app.js
    var app = angular.module('myngapp',['ngRoute','ngCookies','ui.bootstrap','kendo.directives','pascalprecht.translate','tmh.dynamicLocale']);

    app.config(['$routeProvider', '$httpProvider', '$translateProvider', 'tmhDynamicLocaleProvider', '$compileProvider', function($routeProvider, $httpProvider, $translateProvider, tmhDynamicLocaleProvider, $compileProvider) {
    'use strict';

    $compileProvider.debugInfoEnabled(false);

    $routeProvider.otherwise({
        redirectTo: '/login'
    });
    }]);

В myModule.js

  app.requires.push('app.myModule');

и в вашем index.html, включите app.js first и myModule.js next. Таким образом, вы можете включить n количество модулей без изменения app.js.

Включите myModule.js на лету из app.js

var mainHead = document.getElementsByTagName('HEAD').item(0);
var myScript= document.createElement("script");
myScript.type = "text/javascript";
mainHead.appendChild( myScript);
myScript.src='../myModule.js';
myScript.onload = function(){
     angular.element(document).ready(function() {
                      angular.bootstrap(document, ['myngapp']);
                     });
     }

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

Ответ 5

Я знаю, что это не очень красиво, но как сделать следующее:

var injectedDependencies = [.....];
angular.prevmodule = angular.module;
angular.module = function(name, params){
    if(params){
        params.push(injectedDependencies);
    }
    return angular.prevmodule.apply(angular, arguments);
}

edit: обратите внимание, что это полезно, если вы хотите вводить модули, не имея при этом приложения, чтобы знать их (для exapmple для ведения журнала, мониторинга, безопасности и т.д.), но не для того, чтобы вы захотели ввести инъекцию после того, как приложение было загружено.

Ответ 6

Я борюсь с той же проблемой. Я думаю, http://blog.getelementsbyidea.com/load-a-module-on-demand-with-angularjs/ может делать то, что вы хотели.

В своем github https://github.com/ocombe/ocLazyLoad вы можете найти:

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