How to Modularize AngularJS app(folder structure)? - angularjs

Assume I am going to start new AngularJs app with 3 modules:
login
payment
enquiry
I want to load payment module with login details similarly for enquiry, how can we achieve this?
I will have 1 login screen which will call server and check for login, after that server will respond with some parameter which I will use in payment and enquiry module.
If I load login module with other 2 modules:
var myModule = angular.module('myApp', ['payment', 'enquiry']);
It will load both modules on login (I am not sure), but i want like this:
var myModule = angular.module('myApp', ['login']);
// i.e for payment:
var myModule = angular.module('payment', ['login']);
// and for enquiry:
var myModule = angular.module('enquiry', ['login']);
Only login should be loaded. I will use login parameters here.
Any suggestions?

Firstly, you are not "loading" the modules with that syntax, only making sure that they are initialized in the right order. Loading the modules is done by including them in your index.html page (or by using requirejs or similar, but that will make it a completely different beast).
Assuming you are building a SPA (Single Page Application) you will only have one main module, and that will have to reference all other modules you want to use, directly or indirectly. So if you do it the way you want, you will never be able to access payment or enquiry. So you should do:
in app.js
var myModule = angular.module('myApp', ['payment', 'enquiry']);
in payment.js
var myModule = angular.module('payment', ['login']);
in enquiry.js
var myModule = angular.module('enquiry', ['login']);
in login.js
var myModule = angular.module('login', []);
in index.html
<html ng-app="myApp">
...
<script src="app.js"></script>
<script src="payment.js"></script>
<script src="enquiry.js"></script>
<script src="login.js"></script>
...
</html>
And remember since you will be including the JavaScript code for all these in the index.html you will "load" all the code always no matter how you define your modules, you will also only have one module "bound" to your application, and that module will have to have access to all other modules you are including.
If you however want to do lazy loading (load resources (modules, controllers, filters, providers etc.) when you need them that is a completely different beast and will require a lot of extra code all over your applications as well as some hackish ways of using angularjs, unless you use something, http://marcoslin.github.io/angularAMD/#/home. There is also a good discussion on if you should or should not use lazy loading here: Does it make sense to use Require.js with Angular.js?

Related

AngularJs modules LazyLoading

At work we use a global module/main-app
<html ng-app="mainApp" />
First of all, is it good or bad to use a global module?
Second, I don't want to load all dependencies in this global module so I want to use a lazy loader, but what do you think of this solution?
// Set my module as main module
$("#ng-app").attr("ng-app", "myModule");
// Load the global module and another directive
var app = angular.module('myModule', ["mainApp", "angucomplete"]);
I want to mention that I am using AngularJS with CodeIgniter so I'm loading the JS script in view rather than include it in module dependencies.
I'm using lazy load because I use require.js... if you need, you can put at end of your js:
angular.bootstrap(document, ['mainApp']);
See this sample on: jsbin

Dynamically loading controller with angularjs and requirejs

I am trying to integrate angularjs app with requirejs. I want to preload templates and controllers on-demand. In my example:
http://plnkr.co/edit/vIps7t92OFzA5RXoTjvI?p=preview
I init controller SocialController inside the app.js and I need to load dynamically StreamController inside the SocialController. Unfortunately I am getting an exception, see browser console.
Argument 'StreamController' is not a function, got undefined
If I remove from SocialController
angular.module('sampleTest').controller('StreamController', StreamController);
and add it to app.js, it works but in this case requirejs will preload it right at the beginning and not when I need, inside the SocialController on demand.
Here is an answer. Looks like angular does not allow instantiating any new services or controllers later on, after the app startup. So the code below I had to add to app.js files at the bottom, after all the controller and services are init. This is a hack but fixes the problem for lazy loading with requirejs.
See my link to plunkr with the fix. Now there are no exception and StreamController is lazy loaded and init after the startup.
sampleApp.config(
function (
$controllerProvider,
$compileProvider,
$filterProvider,
$provide
) {
sampleApp.controller = $controllerProvider.register;
sampleApp.directive = $compileProvider.directive;
sampleApp.filter = $filterProvider.register;
sampleApp.factory = $provide.factory;
sampleApp.service = $provide.service;
}
);

Dynamically Add Dependencies in AngularJS

I have a JS file with Angular controllers etc. that are used on lots, or many pages. It starts with the line:
var fb = angular.module( 'fb', ['fb.controllers','fb.directives','fb.services','ui.bootstrap'] );
The JS file also contains Angular controllers etc. that are used rarely, that depend on 'ui.bootstrap'.
What solutions are available to move my Angular code to separate JS files and only including the dependency 'ui.bootstrap' when I need it?
You are right, it is strongly recommended to separate such things and also to create one file per controller/directive/filter/etc.
Once you registered module you can use it in the other js files. Angular automatically resolve dependencies.
For example, in fb-controllers.js you register 'fb.controllers' module which depends on 'ui.bootstrap':
angular.module('fb.controllers', ['angular.ui']);
in fb-directives.js you register 'fb.directives' module which ot depends on 'ui.bootstrap':
angular.module('fb.directives', []);
then in app.js you register your main module with dependencies on other:
var fb = angular.module( 'fb', ['fb.controllers','fb.directives']);

Can I have two angular.module calls to the same ng-app in two different files?

I have an angular.js app that is declared with ng-app="audioApp" in the <body> tag of the html file.
If I have an angular.module call in one javascript file:
var app = angular.module('audioApp', []);
Can I make another identical angular.module call in a different javascript file? My application is mysteriously breaking with this second angular.module call, so it seems I can not have this call twice.
Any suggestions to a solution would be appreciated.
Yes. You need to omit the , [] part.
var app = angular.module('audioApp');
That'll grab a reference to the module, rather than redefine it.
What I like to do is keep a module.js file, which comes before any files which depend on the module or extend it.
audioApp.js
var app = angular.module('audioApp', ['some', 'deps']);
someDirective.js
var app = angular.module('audioApp');
app.directive(...);
someController.js
var app = angular.module('audioApp');
app.controller();

re-open and add dependencies to an already bootstrapped application

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.
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');
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!
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.
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>
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 the link to google groups that was provided in 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']);.
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.

Resources