AngularJS loading modules - angularjs

I'm having a really hard time trying to make modules working on an app I'm building.
This is the main file
main.js
'use strict';
angular.module('clientPortalPublic',[
'ngCookies',
'ngResource',
'ngAnimate',
'clientPortalPublic.components'
]);
angular.module('clientPortalPublic.components',[]);
And I have another file switch-login-effect.js
'use strict';
angular.module('clientPortalPublic.components').directive('switchLoginEffect',['$timeout', function($timeout){
//Content removed for clarification
}]);
The order that those files are being loaded is:
<script type="application/javascript" src="public/components/switch-login-effect.js"></script>
<script type="application/javascript" src="public/main.js"></script>
I know the switch-login-effect.js should be loaded later, since is requiring the main module, but it's being loaded dynamically and I don't control the order. BUT using manual bootstrapping shouldn't angular deal with it?
This is how I'm bootstrapping it
angular.element(document).ready(function() {
angular.bootstrap(document, ['clientPortalPublic']);
});
If I run the code above I get:
Error: [$injector:nomod] Module 'clientPortalPublic.components' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
Thanks!

You are declaring a directive on a non-existant module when switch-login-effect.js loads first. It looks like you are trying to dynamically control what elements are included in the clientPortalPublic.components module simply by adding or removing scripts, but I don't think angular's dependencies are set up for that. A main reason to have those dependencies is to know exactly what you are getting.
The clientPortalPublic.components module should be defined in one script file if possible. If you have various components you can create different modules for each, but the definition of your application module should know what it is getting by the dependencies it requires. That would cause debugging headaches for one reason, "Why is my directive not working? I'm loading the components module..." (but you missed a script file you have no way to know that you need)
I really don't advise creating your app this way, but if you are dead-set you could catch the error and create the module at the start of each individual component file (and in your main.js in case you don't actually have any components but still want to require the module) so it doesn't matter which one is loaded first:
try {
angular.module('clientPortalPublic.components');
} catch (err) {
angular.module('clientPortalPublic.components',[]);
}
Or more simply just uses javascript to see if it's been executed:
var componentsModule = componentsModule ||
angular.module('clientPortalPublic.components',[]);

After reading some angular good practices and paying more attention to angular seed, I have it working.
THe thing is that they recommend to do the following when you have an structure similar to:
app/
app/components
app/components/component1
app/components/component2
app.js => angular.module('main',['main.components']);
app/components/components.js => angular.module('main.components',['main.components.component1', 'main.components.component2']);
app/components/component1.js => angular.module('main.components.component1',[]);
app/components/component2.js => angular.module('main.components.component2',[]);
Having that structure make sense and works perfectly.
:)

Related

How to inject a module and make it accesible to all modules and submodules of app (getting unknown provider error)

Please note this is not a duplicate of:How to inject module and make it accesible to entrie angular app
I have a module (app.config) that I would like to inject into my entire app.
The module needs to be accessible within all other modules and submodules(modules inside modules) injected into myApp
For example, my app looks like this:
angular.module('myApp', [
'app.config',
'module#1',
'module#2',
'module#3',
'module#4'
])
.config...
/////////////////////////////////
Here's app.config
angular.module('app.config', []).
constant('NAME1', 'Name1').
constant('NAME2', 'Name2');
////////////////////
I want 'app.config' injected in such a way that it should be accesible in module#500 which is not directly a dependecy of 'myApp', but a dependecy of module#1 - which, in turn, is a dependecy of myApp.
module#1 is defined as such (as shown,module#500 is a dependecy of module#1):
angular.module('module#1', [
'module#500',
'module#501',
'module#502',
...
]);
Here's my problem:
angular.module('module#500', []).
service('serviceOne', serviceOne);
function ServiceOne($http, NAME1) {
var service = {
getMyProfile: function(){return $http.get('api/' + NAME1);}
};
return service;
}
Problem - I get an error-> Uncaught Error: [$injector:unpr] Unknown provider: NAME1Provider <-NAME1 <- serviceOne But I thought I injected it to the entire app???
I don't want to add module#500 directly as dependency to 'myApp' I wan't to leave module#500 as a dependecy of module#1. And I want to leave module#1 as a dependency of myApp
I don't want to individually inject app.config to each and every module either. Any other solutions?
I don't want to individually inject app.config to each and every
module either. Any other solutions?
I don't know what solution you could be expecting? With this line: angular.module('module#500', []). how is module#500 going to know about anything else, it has nothing given to it. Maybe I'm misunderstanding something here.
edit, as I've just read your post and comments from yesterday: I think you're not understanding dependency-injection properly. It only goes one way, module#1 has access to module#500, but module#500 doesn't have access to module#1. It has to be that way: How could you unit-test module#500 if it has some behavior that depends on module#1, which is not mentioned anywhere in its code?
I'm guessing your project doesn't really call for so many modules, if they all depend on the same config variables. Those factories and services that depend on the config variables should be in the same module with it. That is proper compartmentalization and will make your life easier in the long run.
If you don't want to make myApp dependent on app.config (though it would be the right thing to do because its submodules depend on it), you can load config module with manual bootstrapping
angular.bootstrap(document, ['myApp', 'app.config']);
instead of ng-app="myApp".
You forgot to inject NAME1 in your ServiceOne service.
eg: function ServiceOne($http, NAME1)

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

Loading multiple controllers in seperate files asynchronously with angular-loader and scriptjs

I started an angular project using angular-seed, and with index-async.html it uses angular-loader and script.js by default. I added two controllers to this project, each in two separate files.
The file for the first controller starts like this:
angular.module('myApp.controllers').controller('FirstCtrl', ...
The file for the second controller starts like this:
angular.module('myApp.controllers').controller('SecondCtrl', ...
And then in the main app.js file:
angular.module('myApp.controllers', []);
angular.module('myApp', [
'myApp.controllers'
])
All three files were added to script.js:
$script([
'bower_components/angular/angular.js',
'bower_components/angular-route/angular-route.js',
'js/app.js',
'js/controllers/first-ctrl.js',
'js/controllers/second-ctrl.js',
], function() {
angular.bootstrap(document, ['myApp']);
});
When I run the app, sometimes it works, and sometimes I get the errors:
Uncaught Error: [$injector:nomod] http://errors.angularjs.org/1.2.20/$injector/nomod?p0=myApp.controllers
Error: [ng:areq] Argument 'FirstCtrl' is not a function, got undefined
Note. I've left out routeprovider for brevity, but I go to the route with FirstCtrl first. I get similar issue if I go to route with SecondCtrl instead.
I don't think I've changed too much with angular-seed so am wondering if I'm doing it right with adding more controllers?
I've found that the $script.js v2 (not released yet) already support the parallel script loading but also preserve the order of execution.
You can try upgrading it by copy content in the below file and replace the old one in index-async.html.
https://github.com/ded/script.js/blob/v2/src/script.js

Multiple modules loading error

I have several modules in my application, every module definition in separated js file:
angular.module('app', ['app.module1']);
angular.module('app.module1', ['app.module1.module2']);
angular.module('app.module1.module2', []);
And then I want to create controller for last module:
angular.module('app.module1.module2').controller('myController', function(){});
In this case I have error
Module 'app.module1.module2' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
Could anyoune explain where is the problem? Sorry for newbie question.
Note: every definition in it's own js file.
You cant use a module before it is created, so you must be carefull in which order you load then ,load the module definition first then you can reopen the module in a file loaded after the module definition file.
However it makes more sense to stick to one one module per file. That way you dont have to care in which order your module are declared.
so you could write thing instead :
angular.module('app.module1.module2.controllers',[])
.controller('myController', function(){});
then
angular.module('app.module1.module2', ['app.module1.module2.controllers']);
even if you load app.module1.module2 after app.module1.module2.controllers it will work.

In Angular, is there a reason not to list module dependencies with the module declaration?

In all the tutorials and examples I've read regarding Angularjs, they all define modules with an empty list as the second parameter:
angular.module('myModule', []);
I understand that the presence of the second parameter is required to create a new module, but I don't understand why there are never any elements in the list. The document for angular.module says nothing about what the contents of the list would represent.
However, from defining my app module I understand the list represents modules upon which the new module depends - so why is it always empty for app sub-modules? For example, in my own project I've got a users module upon which my app depends:
/* app.js */
angular.module('myApp', [
'ngCookies',
'ngResource',
'ui.bootstrap',
'ui.router',
'myApp.system',
'myApp.users'
]);
angular.module('myApp.system', []);
angular.module('myApp.users', []);
When I finally got around to learning how to unit test using karma and jasmine, I spent hours trying to figure out this error message:
Error: [$injector:modulerr] Failed to instantiate module myApp.users due to:
Error: [$injector:unpr] Unknown provider: $stateProvider
http://errors.angularjs.org/1.2.13/$injector/unpr?p0=%24stateProvider
at /Users/matt/Development/myApp/public/lib/angular/angular.js:3556
at getService (/Users/matt/Development/myApp/public/lib/angular/angular.js:3683)
at invoke (/Users/matt/Development/myApp/public/lib/angular/angular.js:3710)
at /Users/matt/myApp/public/lib/angular/angular.js:3639
Eventually I found two things that would fix this problem - either I could load module dependencies in the test code, or I could add the dependencies to the empty list in the users module declaration:
/* UserControllerTest.js */
describe('UserCtrl', function () {
var $rootScope,
$scope,
controller;
beforeEach(function () {
module('ui.router');
module('myApp.system');
module('ngResource');
module('myApp.users');
inject(function ($injector) {
$rootScope = $injector.get('$rootScope');
$scope = $rootScope.$new();
controller = $injector.get('$controller')('UserCtrl', {$scope: $scope});
});
});
it('should work', function () {
expect(true).toBe(true);
});
});
Or:
/* app.js */
...
angular.module('myApp.users', [
'ngResource',
'ui.router',
'mean.system'
]);
Is there some reason I wouldn't want to do the latter? Why is it that I never see that in docs and tutorials - would it prevent me from being able to mock those dependencies in testing?
Why is it that I don't need the latter sub-module definition for regular operation of my app? I do have a series of 'injection locals' specified for UserCtrl - why isn't that sufficient for the unit test?
The purpose of modules is to encapsulate self-contained parts of code (e.g. a reusable widget, code tgst implements a specific feature etc). In general, it is a good practice to have each module declare the dependencies it relies upon.
If not, then the module relies on the modules thst require it to declare those dependencies, which messes "self-containment", hurts testability and reusability and introduces a bunch if potential future bugs.
That said, there doesn't seem to be a reason not to declare dependencies with each module. (And no, it will not prevent you from mocking the dependencies in unit tests.) Of cource, as one would expect, each module is loaded once even if it is required by several modules.
The API reference is indeed not very detailed about angular.module, but the Developer Guide has a more extensive description.
E.g., quoting the "Dependencies" section:
Modules can list other modules as their dependencies. Depending on a module implies that required module needs to be loaded before the requiring module is loaded. In other words the configuration blocks of the required modules execute before the configuration blocks of the requiring module. The same is true for the run blocks. Each module can only be loaded once, even if multiple other modules require it.

Resources