Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Opinionated whitespace guide for AngularJS modules

AngularJS Whitespace Guide

The purpose of this style guide is to suggest formatting conventions for AngularJS modules that result in readible, maintainable, and lint free code (see the linter configurations for JSHint and gjslint.py.

All-in-one example

Typically, an AngularJS application would be structured with many modules in separate files. The example below shows a monolithic module to illustrate the formatting conventions for various module methods.

angular.module('module.name', [
  'dependency.one',
  'dependency.two'
])
.animation('.animation-name',
    function(injectable1, injectable2) {
      // animation factory here
      return {};
    })
.config(
    function(injectable1, injectable2) {
      // config function here
      injectable1.foo(injectable2);
    })
.constant('NamedFunction',
    function(value) {
      // constant function here
      return value * 2;
    })
.controller('NamedCtrl',
    function(injectable1, injectable2) {
      // controller constructor here
      this.foo = injectable1() + injectable2();
    })
.factory('NamedService1',
    function(injectable1, injectable2) {
      // service factory here
      return {};
    })
.service('NamedService2',
    function(injectable1, injectable2) {
      // service constructor here
      this.foo = injectable1() + injectable2();
    })
.directive('NamedDirective',
    function(injectable1, injectable2) {
      // directive factory here
      return {};
    })
.value('var1', 123);

Details

These formatting guidelines assume that before minifying your code, you process it with ngmin to generate minifier-safe inline annotations for injectables (ngmin is available as a Grunt plugin, a Rails gem, and Optimus middleware).

The guidelines assume 2 spaces for tabs and a maximum 80 character line length.

Module registration

angular.module('module.name', [
  'dependency.one',
  'dependency.two'
])

The module name and opening bracket for the dependency array are on the same line as angular.module. Module dependencies are listed one per line. Closing bracket and parenthesis are on their own line. The justification for this is that the module name is clearly separated from dependencies, and dependencies are easy to add or remove without extra changes related to line wrapping.

Module configuration

// module registered above
.config(
    function(injectable1, injectable2) {
      // config function here
    });

The .config( call is on its own line, with the function argument indented 4 spaces on the following line. This follows the pattern for other providers below. A semicolon ends the statement (leave the semicolon off if there are more call expressions in the same file).

The angular.Module methods that take a name and a factory or constuctor (e.g. controller, directive, factory, etc.) are all written in a similar way.

// module registered above
.controller('NamedCtrl',
    function(injectable1, injectable2) {
      // controller constructor here
      this.foo = injectable1() + injectable2();
    });

The first argument (the name of the controller, service, filter, etc.) goes on the same line as the method and opening parenthesis. The factory or constructor function begins on a new line and is indented 4 spaces (function arguments that are on a new line get two tabs). The closing parenthesis immediately follows the closing brace for the function. Omit the semicolon if there are more method calls on the module in the same file.

A value or constant call goes on a single line if shorter than 80 characters.

// module registered above
.value('var1', 123);

Edge cases

Functions with a ton of arguments

If a function requires more arguments than fit on a single 80 character line, wrap arguments and indent with two tabs (4 spaces).

// module registered above
.factory('NamedService1',
    function(injectable1, injectable2, injectable3, injectable4, injectable5,
        injectable6, injectable7, injectable8, injectable9, injectable10) {
      // service factory here
      return {};
    });

(Functions with many arguments would be discouraged as they are harder to reason about, but this is just a whitespace guide.)

Calls to constant or value with big object literals

It should be possible to indent big object literals as follows:

// module registered above
.constant('NamedObject', {
  property1: 'value1',
  property2: 'value2'
})

Unfortunately, gjslint.py complains about this - expecting 6, 10, or 14 spaces of indentation before property1 instead of 2. When gjslint.py is satisfied, JSHint complains that property1 needs 2 spaces indentation and the closing brace needs no indentation. Where possible, the object literal can be written on a single line. Where this is not possible, the following (ugly) format satisfies both linters:

// module registered above
.constant('NamedObject',
    {property1: 'value1', property2: 'value2', property3: 'value3',
      property4: 'value4'})
{
"curly": true,
"eqeqeq": true,
"indent": 2,
"latedef": true,
"newcap": true,
"nonew": true,
"quotmark": "single",
"undef": true,
"trailing": true,
"maxlen": 80,
"globals": {
"angular": false
}
}
/** SublimeLinter user settings for gjslint.py */
{
"sublimelinter": true,
"sublimelinter_popup_errors_on_save": true,
"javascript_linter": "gjslint",
"gjslint_options": ["--strict", "--custom_jsdoc_tags=todo"],
"gjslint_ignore": []
}

Nice guide but how do you format something like:

.controller('NamedCtrl', ['injectable1', 'injectable2', function(injectable1, injectable2) {
  // ...
}]);

It always looks so messy.

gortok commented Aug 3, 2015

@scheffield I typically put one per line as well, in Alpha order ($ declarations in alpha order, then non $ declarations in Alpha order; so like:

.controller('NamedCtrl', [
  '$a',
  '$baz,'
  'bar',
  'foo',  
 function(
  $a,
  $baz,
  bar, 
  foo) {
    // ...
}]);
wdlb commented Aug 7, 2015

@scheffield We would do it like this:

angular.module("app.controllers").controller("NamedController", NamedController);
NamedController.$inject = ["$a", "$b", "bar", "foo"];
function NamedController($a, $b, bar, foo) {
    // ...
}

based on the following rules of John Papa's Angular Styleguide:

following this approach made our code much more pleasant to read (IMHO)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment