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']);
Related
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
In the following plunkr, can anyone explain why I have to inject 'ui.router' into the first listed submodule, but not any of the subsequent submodules?
http://plnkr.co/edit/nCBeMAKrxvL9CHvLzRdL?p=preview
I thought the ui.router dependency would be available to every submodule after doing this:
angular.module('myapp', ["myapp.route1", "myapp.route2", "ui.router"])
Instead, i have to include ui.router in the first listed dependency (in this case myapp.route):
angular.module('myapp.route1', ["ui.router"])
but not in myapp.route2:
angular.module('myapp.route2', [])
What am I missing?
The loading order depends on the order of declared dependencies, so
angular.module('myapp', ["myapp.route1", "myapp.route2", "ui.router"])
means that "myapp.route1" loads first (in config phase - this doesn't apply to run-phase), and it also loads "ui.router". And, so, when "myapp.route2" loads, "ui.router" service are already loaded.
Changing the order of declared dependencies breaks this.
So, clearly, you should not rely on this. Each module should declare its own dependencies.
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.
:)
I'm building an app with MEAN.JS and I'm trying to use a controller from another module. I've found that I can do this with dependency injection:
angular.module(‘MyModule’, [‘Dependency’]);
But the way modules are created in MEAN.JS is:
ApplicationConfiguration.registerModule('MyModule');
And I can't just pass a second parameter to registerModule. So, how should I do this? Do I have to use both methods? Am I doing it wrong?
Example
I want to add a new model: Campaign. Campaigns are created by admins only, but can be seen by the "campaign owner" (another User). The create campaign form should list available Users, so the admin can select the one that's going to be the "owner" of that Campaign.
The problem is, the create campaign form is controlled by CampaignsController, how can I list Users? I've used another controller (UsersController) and thats the problem, it is undefined because we are in the Campaign module.
EDIT:
The problem was grunt autorestarting the app incorrectly:
I moved the controller from one module (folder) to another, but grunt was still trying to load it from the old path, and thus failing: Controller not found. I thought the problem was dependency injection, but you only have to close grunt (Ctrl+C) and run it again. Problem solved.
Anyways, thanks for the answer #gilBirman cause it is correct: there is no need to inject anything with MEANJS.
MEAN.js makes all the modules registered via registerModule available to all other modules in your app by adding it as a dependency to the main app called mean. Here's the part of the MEAN.js source code that does this:
var applicationModuleName = 'mean';
....
// Add a new vertical module
var registerModule = function(moduleName) {
// Create angular module
angular.module(moduleName, []);
// Add the module to the AngularJS configuration file
angular.module(applicationModuleName).requires.push(moduleName);
};
So you're on the right track, however it sounds like you are trying to inject a controller. However, in angular, controllers are not injectable. You can inject services, factories, values, and constants.
First create your own module for example:
angular.module('app.controllers', []) - angular module with controllers.
then add controller to that module:
angular.module('app.controllers', [])
.controller('dashboard.admin.account.controller', ['$scope', ($scope) { .... }]);
then create global module which will bind to your markup:
angular.module('app', [
'app.controllers'
'ui.router',
'ngAnimate'
]);
then bootstrap your global module to markup:
domReady(function () {
angular.bootstrap(document, ['app']);
});
Now you can use your controller.
I've seen some projects keep all the "pieces" (controllers/services/directives) to a module in one file. angular-app does it like that.
example:
angular.module('myModule', ['depA', 'depB'])
.controller('MyController', function() {})
.service('myService', function() {});
However I've worked on teams in the past on large angular projects where individual controllers/services/directives were kept in their own files. I like the idea of keeping them in their own files to keep the files small among other reasons. The problem now is that I'm the one in charge of getting the beginning pieces and build process put together. All I had to do before was write application code and follow the standard on those projects.
In order to have separate files properly, I believe I would have to have one main module file.
example:
// file 1
angular.module('myModule', ['depA', 'depB']);
// file 2
angular.module('myModule')
.controller('MyController', function() {});
So my question is, what file loading order do I need to make sure happens? Do I only need to make sure that the main module file (file 1) is loaded before file 2?
That seems odd to me. If there was also a service file attached to the previously mentioned module and the controller file 2 was already loaded, but the service file wasn't yet, isn't it possible that angular could invoke that controller file and then eventually cause things to get out of whack?
Also, if you think I'm handling this the wrong way I would love to hear your suggestions.
Module Load Order
Just make sure that when you register a new module, by the time your application bootstraps, it's module dependencies should have already been loaded by the browser.
So anytime you do this:
angular.module('myApp', ['dep1', 'dep2', 'dep3']);
The files with dep1, dep2, and dep3 should have already been loaded by the time your application bootstraps.
If you are using <script> tags and automatic bootstrapping (the angular default) then the order of your <script> tags shouldn't matter. However, if using a library like requirejs make sure that all of your dependencies are loaded before manually bootstrapping.
Additional Considerations
As long as your modules are loaded in the correct order, then..
There is no need to worry about the order of controllers, directives, services, factories, providers, constants, or values
The order of run blocks may be important only as they relate to other run blocks since they are executed in the order in which they are registered (within a specific module).
The order of config blocks may be important only as they relate to other config blocks since they are executed in the order in which they are registered (within a specific module).
In regards to the prior 2 points, the order of dependencies (for example ['dep1', 'dep2', 'dep3'] vs ['dep2', 'dep3', 'dep1']) will also effect the order of execution of run blocks and config blocks. Angular will traverse the dependency tree twice and execute, in order, all config blocks followed by all run blocks.
Angular uses a post-order traversal to initialize modules and their associated config and run blocks. So if we represent our module dependencies as a tree:
The order of traversal is ACEDBHIGF
What I do on my projects, is keep everything separate in the developing environment, but then compile things down via gulp.js (grunt should work as well). That's a separate subject though, but here's an example of how to keep your angular code in different files.
The main file (must be loaded first) could be as follows. We will define our module, controllers, directives, repositories, or whatever else. Let's call it app.js:
// AngularJS Application File
var example = angular.module(
// ngApp name
'example',
// Default Dependencies
[
'exampleControllers',
'exampleRepositories',
'exampleDirectives'
]
);
var exampleControllers = angular.module('exampleControllers', []);
var exampleRepositories = angular.module('exampleRepositories', []);
var exampleDirectives = angular.module('exampleDirectives', []);
Now, we can access this exampleControllers, exampleRepositories, and exampleDirectives from within any javascript file that follows.
controllers.js file.
exampleControllers
// Main Controller
.controller('MainController',
[
'$scope',
'$log',
function ($scope, $log) {
$scope.hello = 'Hello World';
}
]
)
// Sub Page Controller
.controller('SubPageController',
[
'$scope',
'someService',
'$log',
function ($scope, sService, $log) {
$log.info($scope.hello);
}
]
);
anothercontroller.js file:
exampleControllers
// Another Controller
.controller('AnotherController',
[
'$scope',
'$log',
function ($scope, $log) {
$scope.helloagain = 'Hello World, from another controller';
}
]
)
And so forth.. Just make sure your app.js file gets loaded first so the example<whatever> variables are available.
I would definitely read up on gulp.js (http://gulpjs.com/). It's pretty awesome for automating work flows.