116

I have a bunch of Angular modules declared in my app. I originally started declaring them using the "chained" syntax like this:

angular.module('mymodule', [])
    .controller('myctrl', ['dep1', function(dep1){ ... }])
    .service('myservice', ['dep2', function(dep2){ ... }])
    ... // more here

But I decided that wasn't very easy to read, so I started declaring them using a module variable like this:

var mod = angular.module('mymodule', []);

mod.controller('myctrl', ['dep1', function(dep1){ ... }]);

mod.service('myservice', ['dep2', function(dep2){ ... }]);
...

The second syntax seems a lot more readable to me, but my only complaint is that this syntax leaves the mod variable out in the global scope. If I ever have some other variable named mod, it would be overridden with this next one (and other issues associated with global variables).

So my question is, is this the best way? Or would it be better to do something like this?:

(function(){
    var mod = angular.module('mymod', []);
    mod.controller('myctrl', ['dep1', function(dep1){ ... }]);
    mod.service('myservice', ['dep2', function(dep2){ ... }]);
    ...
})();

Or does it even matter enough to care? Just curious to know what the "best practices" are for module declaration.

starball
  • 20,030
  • 7
  • 43
  • 238
tennisgent
  • 14,165
  • 9
  • 50
  • 48
  • 3
    I wondered the same about [Angular Best Practices](http://stackoverflow.com/q/20802798/1959948) – Dalorzo May 17 '14 at 22:40

7 Answers7

117

'Best' way to declare a module

As angular is on the global scope itself and modules are saved to its variable you can access modules via angular.module('mymod'):

// one file
// NOTE: the immediately invoked function expression 
// is used to exemplify different files and is not required
(function(){
   // declaring the module in one file / anonymous function
   // (only pass a second parameter THIS ONE TIME as a redecleration creates bugs
   // which are very hard to dedect)
   angular.module('mymod', []);
})();


// another file and/or another anonymous function
(function(){   
 // using the function form of use-strict...
 "use strict";
  // accessing the module in another. 
  // this can be done by calling angular.module without the []-brackets
  angular.module('mymod')
    .controller('myctrl', ['dep1', function(dep1){
      //..
    }])

  // appending another service/controller/filter etc to the same module-call inside the same file
    .service('myservice', ['dep2', function(dep2){ 
    //... 
    }]);

  // you can of course use angular.module('mymod') here as well
  angular.module('mymod').controller('anothermyctrl', ['dep1', function(dep1){
      //..
  }])
})();

No other global variables are required.

Of course it depends all on preferences, but I think this is kind of the best practise, as

  1. you don't have to pollute the global scope
  2. you can access your modules everywhere and sort them and their functions into different files at will
  3. you can use the function-form of "use strict";
  4. the loading order of files does not matter as much

Options for sorting your modules and files

This way of declaring and accessing modules makes you very flexible. You can sort modules via function-type (like described in another answer) or via route, e.g.:

/******** sorting by route **********/    
angular.module('home')...
angular.module('another-route')...
angular.module('shared')...

How you sort it in the end is a matter of personal taste and the scale and type of the project. I personally like to group all files of a module inside of the same folder (ordered into sub-folders of directives, controllers, services and filters), including all different test-files, as it makes your modules more reusable. Thus in middle-sized projects I end up with a base-module, which includes all basic routes and their controllers, services, directives and more or less complex sub-modules, when I think they could be useful for other projects as well,e.g.:

/******** modularizing feature-sets **********/
/controllers
/directives
/filters
/services
/my-map-sub-module
/my-map-sub-module/controllers
/my-map-sub-module/services
app.js
...

angular.module('app', [
  'app.directives',
  'app.filters',
  'app.controllers',
  'app.services',
  'myMapSubModule'
]);

angular.module('myMapSubModule',[
   'myMapSubModule.controllers',
   'myMapSubModule.services',
   // only if they are specific to the module
   'myMapSubModule.directives',
   'myMapSubModule.filters'
]);

For very big projects, I sometimes end up grouping modules by routes, as described above or by some selected main routes or a even a combination of routes and some selected components, but it really depends.

EDIT: Just because it is related and I ran into that very recently again: Take good care that you create a module only once (by adding a second parameter to the angular.module-function). This will mess up your application and can be very hard to detect.

2015 EDIT on sorting modules: One and a half year of angular-experience later, I can add that the benefits from using differently named modules within your app are somewhat limited as AMD still does not really work well with Angular and services, directives and filters are globally available inside the angular context anyway (as exemplified here). There is still a semantic and structural benefit though and it might be helpful being able to include/ exclude a module with a single line of code commented in or out.

It also almost never makes much sense to separate sub-modules by type (eg. 'myMapSubModule.controllers') as they usually depend on each other.

Community
  • 1
  • 1
hugo der hungrige
  • 12,382
  • 9
  • 57
  • 84
  • 7
    You don't need the IIFE (Immediately Invoked Function Expression), aka anonymous self executing function – plus- Nov 13 '13 at 17:05
  • 1
    You're right. You only need it when you want to apply the function-form of "use strict"; Doesn't hurt though. – hugo der hungrige Nov 13 '13 at 17:12
  • 1
    In most cases you can put `'use strict';` inside your component too. `module.controller(function () { 'use strict'; ... });` – Jackson Jul 05 '14 at 00:30
  • I like implementation, but I am not a fun of chaining either,so I am mixing this to what Beterraba is doing – Paranoid Android Sep 12 '14 at 12:27
  • I prefer this method because you only need to declare common dependencies once - .i.e. in the original module definition. – gbro3n Feb 04 '15 at 14:28
  • 1
    when using AMD, one single module named app is enough. One can exclude a AMD module by deleting the require statement. And we don't need to register the controllers and services any more. – James Apr 02 '15 at 15:49
28

I love the angular-styleguide by Johnpapa, and here are some rules that related to this question:

Rule: Named vs Anonymous Functions

Avoid using anonymous functions:

// dashboard.js
angular
  .module('app')
  .controller('Dashboard', function() { })

Instead, use named functions:

// dashboard.js
angular
  .module('app')
  .controller('Dashboard', Dashboard);

function Dashboard() { }

As the author says: This produces more readable code, is much easier to debug, and reduces the amount of nested callback code.

Rule : Define 1 component per file.

Avoid multiple components in one file:

angular
  .module('app', ['ngRoute'])
  .controller('SomeController', SomeController)
  .factory('someFactory', someFactory);

function SomeController() { }

function someFactory() { }

Intead, use one file to define the module:

// app.module.js
angular
  .module('app', ['ngRoute']);

one file just uses the module to define a component

// someController.js
angular
  .module('app')
  .controller('SomeController', SomeController);

function SomeController() { }

and another file to define another component

// someFactory.js
angular
  .module('app')
  .factory('someFactory', someFactory);

function someFactory() { }

Of course, there are many other rules for modules, controllers and services that are quite useful and worth reading.

And thanks to comment of ya_dimon, the above code should be wrapped in IIFE, for example:

(function (window, angular) {
  angular.module('app')
   .controller('Dashboard', function () { });
})(window, window.angular);
aqingsao
  • 2,104
  • 1
  • 19
  • 18
  • Good answer and great link. – Ellesedil Aug 19 '15 at 21:58
  • if i have different controllers in different javascript files wont it require loading of more number of files i.e more server hits? – Vignesh Subramanian Sep 02 '15 at 03:59
  • It's quite easy to merge/uglify/rename them with gulp or grunt, vignesh, and personally I love gulp. – aqingsao Sep 02 '15 at 07:52
  • 1
    you forgot to add, that all this snippets should be in IIFE, otherwise you have functions like "someFactory()" globally. There is a chance for name collisions. (and you dont need IIFE in es6) – ya_dimon Mar 25 '16 at 14:03
12

I recently had this conundrum as well. I had started off just like you using the chained syntax, but in the long run it becomes unwieldy with large projects. Normally I'd create a controllers module, a services module and so on in separate files and inject them into my main application module found in another file. For Example:

// My Controllers File
angular.module('my-controllers',[])
    .controller('oneCtrl',[...])
    .controller('twoCtrl',[...]);

// My Services File
angular.module('my-services',[])
    .factory('oneSrc',[...])
    .facotry('twoSrc',[...]);

// My Directives File
angular.module('my-directives',[])
    .directive('oneDrct',[...])
    .directive('twoDrct',[...]);

// My Main Application File
angular.module('my-app',['my-controllers','my-services','my-directives',...]);

But each one of these files was getting way to large as the project grew. So I decided to break them up into separate files based on each controller or service. I found that using angular.module('mod-name'). without the injection array, is what you need for this to work. Declaring a global variable in one file and expecting that to be readily available in another just doesn't work or could have unexpected results.

So in short my application looked something like this:

// Main Controller File
angular.module('my-controllers',[]);

// Controller One File
angular.module('my-controllers').controller('oneCtrl',[...]);

//Controller Two File
angular.module('my-controllers').controller('twoCtrl',[...]);

I did this to the services file as well, no need to change the main application module file you'd still be injecting the same modules into that.

m.e.conroy
  • 3,508
  • 25
  • 27
  • 1
    what's the point of creating separate modules for services / directives / controllers? – Filip Sobczak Oct 31 '14 at 12:29
  • 2
    In large projects things can get tough to find when controllers / filters/ directives / services are all interleaved together. This is just one way of keeping things organized. – m.e.conroy Oct 31 '14 at 13:36
  • 1
    @FilipSobczak He is NOT creating separate modules for services / directives / controllers. Rather, he has created the module only once using `angular.module('my-controllers',[]);` (Note that he is specifying the [] only once for declaration). He is simply reusing this in the other files. Separation of files makes it relatively easy to maintain the project, especially big ones. – Devner Jan 04 '16 at 09:35
8

One other practice is to stuff controllers, directives, etc in their own modules and inject those modules into your "main" one:

angular.module('app.controllers', [])
  .controller('controller1', ['$scope', function (scope) {
    scope.name = "USER!";
  }]);

angular.module('app.directives', [])
  .directive('myDirective', [function () {
    return {
      restrict: 'A',
      template: '<div>my directive!</div>'
    }
  }]);

angular.module('app', [
  'app.controllers',
  'app.directives'
]);

Nothing is left in the global scope.

http://plnkr.co/edit/EtzzPRyxWT1MkhK7KcLo?p=preview

Manny D
  • 20,310
  • 2
  • 29
  • 31
  • Why are you using `app.controllers` insted of `controllers` as the module name, Is there any advantage ? I'm a newcomer in Angularjs – sijo vijayan Jul 22 '16 at 10:07
4

I like to divide my files and my modules.

Something like this:

app.js

var myApp = angular.module('myApp', ['myApp.controllers', 'myApp.directives', 'myApp.services']);

myApp.config(['$routeProvider', function($routeProvider) {
    /* routes configs */
    $routeProvider.when(/*...*/);
}]);

directives.js

var myDirectives = angular.module('myApp.directives', []);

myDirectives.directive( /* ... */ );

service.js

var myServices = angular.module('myApp.services', []);

myServices.factory( /* ... */ );

Im not a big fan of the "chained style", so I prefer to write down my variable always.

Beterraba
  • 6,515
  • 1
  • 26
  • 33
  • 2
    This is the way I had been doing it but, each services.js or controller.js file gets big fast in a large scale project, eventually you'll need to break each service or controller out to a separate file. – m.e.conroy Nov 13 '13 at 15:48
  • 1
    @m.e.conroy Exactly. When the thing become bigger and bigger, I like to break the directive into smaller modules and inject then to the "main" directive module. – Beterraba Nov 13 '13 at 15:53
1

I suggest to follow Angularjs Style Guide.
They handle all concept from naming convention, to modularize your app and so on.

For angular 2, you can check Angular 2 Style Guide

user3444693
  • 464
  • 4
  • 7
0

For me, chaining is the most compact way:

angular.module("mod1",["mod1.submod1"])

 .value("myValues", {
   ...
 })

 .factory("myFactory", function(myValues){
   ...
 })

 .controller("MainCtrl", function($scope){

   // when using "Ctrl as" syntax
   var MC = this;
   MC.data = ...;
 })
 ;

That way I can easily move components between modules, never need to declare the same module twice, never need any global variables.

And if the file gets too long, solution is simple - split into two files, each declaring its own module at the top. For more transparency, I try to keep one unique module per file and name it resembling the full path of the file. This way also I never need to write a module without [], which is a common pain point.

Dmitri Zaitsev
  • 13,548
  • 11
  • 76
  • 110