re-open and add dependencies to an already bootstrapped application

AngularjsDependency InjectionBootstrapping

Angularjs Problem Overview


Is there a way to inject a late dependency to an already bootstrapped angular module? Here's what I mean:

Say that I have a site-wide angular app, defined as:

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

And in every page:

<html ng-app="App">

Later on, I'm reopening the app to add logic based on the needs of the current page:

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

Now, say that one of those on-demand bits of logic also requires their own dependencies (like ngTouch, ngAnimate, ngResource, etc). How can I attach them to the base App? This doesn't seem to work:

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

I realize I can do everything in advance, i.e -

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

Or define every module on its own and then inject everything into the main app (see here for more):

// 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'])

But this will require I initialize the App everytime with the current page's dependencies.

I prefer to include the basic app.js in every page and simply introduce the required extensions to each page (reports.js, home.js, etc), without having to revise the bootstrapping logic everytime I add or remove something.

Is there a way to introduce dependencies when the App is already bootstrapped? What is considered the idiomatic way (or ways) to do this? I'm leaning towards the latter solution, but wanted to see if the way I described could also be done. thanks.

Angularjs Solutions


Solution 1 - Angularjs

I solved it like this:

reference the app again:

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

then push your new requirements to the requirements array:

app.requires.push('newDependency');

Solution 2 - Angularjs

Simple... Get an instance of the module using the getter like this: var app = angular.module("App");

Then add to the "requires" collection like this: app.requires[app.requires.length] = "ngResource";

Anyway, this worked for me. GOOD LUCK!

Solution 3 - Angularjs

According to this proposal on the Angular JS google group this functionality does not exist as of this moment. Hopefully the core team decides to add this functionality, could use it myself.

Solution 4 - Angularjs

If you wish to add multiple dependencies at once, you can pass them in push as follows:

<script>
    var app = angular.module('appName');
    app.requires.push('dependencyCtrl1', 'dependencyService1');
</script>

Solution 5 - Angularjs

I realize that this is an old question, however, no working answer has yet been provided, so I decided to share how I solved it.

The solution requires forking Angular, so you can't use CDN anymore. However the modification is very small, so I am surprised why this feature doesn't exist in Angular.

I followed https://groups.google.com/forum/#!topic/angular/w0ZEBz02l8s">the link to google groups that was provided in https://stackoverflow.com/a/19719818/5303541">one of the other answers to this question. There I found the following code, which solved the issue:

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

When I added this code to line 4414 in the angular 1.5.0 source code (inside the createInjector function, before the return instanceInjector; statement), it enabled me to add dependencies after bootstrapping like this $injector.loadNewModules(['ngCookies']);.

Solution 6 - Angularjs

Since version 1.6.7 it is now possible to lazy load modules after the app has been bootstrapped using $injector.loadNewModules([modules]). Below is an example taken from AngularJS documentation:

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

Please read full documentation about loadNewModules as there are some gotchas around it.

There's also a very good sample app by omkadiri using it with ui-router.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionsa125View Question on Stackoverflow
Solution 1 - AngularjsAlBaraa ShView Answer on Stackoverflow
Solution 2 - AngularjsDavid DonovanView Answer on Stackoverflow
Solution 3 - AngularjsMatt NibeckerView Answer on Stackoverflow
Solution 4 - AngularjsAmirView Answer on Stackoverflow
Solution 5 - AngularjstjespeView Answer on Stackoverflow
Solution 6 - AngularjsDenis PshenovView Answer on Stackoverflow