Home

Awesome

Join the chat at https://gitter.im/mgechev/angularjs-style-guide

Introduction

The goal of this style guide is to present a set of best practices and style guidelines for one AngularJS application. These best practices are collected from:

  1. AngularJS source code
  2. Source code or articles I've read
  3. My own experience

Note 1: this is still a draft of the style guide, its main goal is to be community-driven so filling the gaps will be greatly appreciated by the whole community.

Note 2: before following any of the guidelines in the translations of the English document, make sure they are up-to date. The latest version of the AngularJS style guide is in the current document.

In this style guide you won't find common guidelines for JavaScript development. Such can be found at:

  1. Google's JavaScript style guide
  2. Mozilla's JavaScript style guide
  3. Douglas Crockford's JavaScript style guide
  4. Airbnb JavaScript style guide
  5. Idiomatic JavaScript style guide

For AngularJS development recommended is the Google's JavaScript style guide.

In AngularJS's GitHub wiki there is a similar section by ProLoser, you can check it here.

Translations

Table of content

General

Directory structure

Since a large AngularJS application has many components it's best to structure it in a directory hierarchy. There are two main approaches:

In this way the directory structure will look like:

.
├── app
│   ├── app.js
│   ├── controllers
│   │   ├── home
│   │   │   ├── FirstCtrl.js
│   │   │   └── FirstCtrl.spec.js
│   │   │   └── SecondCtrl.js
│   │   │   └── SecondCtrl.spec.js
│   │   └── about
│   │       └── ThirdCtrl.js
│   │       └── ThirdCtrl.spec.js
│   ├── directives
│   │   ├── home
│   │   │   └── directive1.js
│   │   │   └── directive1.spec.js
│   │   └── about
│   │       ├── directive2.js
│   │       ├── directive2.spec.js
│   │       └── directive3.js
│   │       └── directive3.spec.js
│   ├── filters
│   │   ├── home
│   │   └── about
│   └── services
│       ├── CommonService.js
│       ├── CommonService.spec.js
│       ├── cache
│       │   ├── Cache1.js
│       │   ├── Cache1.spec.js
│       │   └── Cache2.js
│       │   └── Cache2.spec.js
│       └── models
│           ├── Model1.spec.js
│           ├── Model1.js
│           └── Model2.spec.js
│           └── Model2.js
├── partials
├── lib
└── e2e-tests

Here is its layout:

.
├── app
│   ├── app.js
│   ├── common
│   │   ├── controllers
│   │   ├── directives
│   │   ├── filters
│   │   └── services
│   ├── home
│   │   ├── controllers
│   │   │   ├── FirstCtrl.js
│   │   │   ├── FirstCtrl.spec.js
│   │   │   └── SecondCtrl.js
│   │   │   └── SecondCtrl.spec.js
│   │   ├── directives
│   │   │   └── directive1.js
│   │   │   └── directive1.spec.js
│   │   ├── filters
│   │   │   ├── filter1.js
│   │   │   ├── filter1.spec.js
│   │   │   └── filter2.js
│   │   │   └── filter2.spec.js
│   │   └── services
│   │       ├── service1.js
│   │       ├── service1.spec.js
│   │       └── service2.js
│   │       └── service2.spec.js
│   └── about
│       ├── controllers
│       │   └── ThirdCtrl.js
│       │   └── ThirdCtrl.spec.js
│       ├── directives
│       │   ├── directive2.js
│       │   ├── directive2.spec.js
│       │   └── directive3.js
│       │   └── directive3.spec.js
│       ├── filters
│       │   └── filter3.js
│       │   └── filter3.spec.js
│       └── services
│           └── service3.js
│           └── service3.spec.js
├── partials
├── lib
└── e2e-tests
app
 ├── app.js
 └── my-complex-module
     ├── controllers
     ├── directives
     ├── filters
     └── services
app
└── directives
    ├── directive1
    │   ├── directive1.html
    │   ├── directive1.js
    │   ├── directive1.spec.js
    │   └── directive1.sass
    └── directive2
        ├── directive2.html
        ├── directive2.js
        ├── directive2.spec.js
        └── directive2.sass

This approach can be combined with both directory structures above.

services
├── cache
│   ├── cache1.js
│   └── cache1.spec.js
└── models
    ├── model1.js
    └── model1.spec.js

Conventions about component naming can be found in each component section.

Markup

TLDR; Put the scripts at the bottom.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>MyApp</title>
</head>
<body>
  <div ng-app="myApp">
    <div ng-view></div>
  </div>
  <script src="angular.js"></script>
  <script src="app.js"></script>
</body>
</html>

Keep things simple and put AngularJS specific directives after standard attributes. This will make it easier to skim your code and will make it easier to maintain because your attributes are consistently grouped and positioned.

<form class="frm" ng-submit="login.authenticate()">
  <div>
    <input class="ipt" type="text" placeholder="name" require ng-model="user.name">
  </div>
</form>

Other HTML attributes should follow the Code Guide's recommendation

Naming conventions

The following table is shown the naming conventions for every element:

ElementNaming styleExampleusage
ModuleslowerCamelCaseangularApp
ControllersFunctionality + 'Ctrl'AdminCtrl
DirectiveslowerCamelCaseuserInfo
FilterslowerCamelCaseuserFilter
ServicesUpperCamelCaseUserconstructor
FactorieslowerCamelCasedataFactoryothers

Others

This will make your testing easier and in some cases prevent unexpected behaviour (for example, if you missed $scope.$apply in setTimeout).

module.factory('Service', function ($rootScope, $timeout, MyCustomDependency1, MyCustomDependency2) {
  return {
    //Something
  };
});

Modules

Controllers

Directives

Filters

Services

This section includes information about the service component in AngularJS. It is not dependent of the way of definition (i.e. as provider, .factory, .service), except if explicitly mentioned.

Templates

    <div ng-controller="MainCtrl as main">
        <div ng-style="main.divStyle">my beautifully styled div which will work in IE</div>;
    </div>
  angular
    .module('app')
    .controller('MainCtrl', MainCtrl);

  MainCtrl.$inject = [];

  function MainCtrl() {
    var vm = this;
    vm.divStyle = {
        width: 200,
        position: 'relative'
    };
  }

Routing

E2E Testing

E2E tests are the next common sense step after unit tests, that will allow you to trace bugs and errors in the behaviour of your system. They are great for providing a sanity check that most common scenarios of using your application works. This way you can automate the process and run it each time before you deploy your application.

Ideally, Angular End-to-End tests are written in Jasmine. These tests are run using the Protractor E2E test runner which uses native events and has special features for Angular applications.

File structure:

.
├── app
│   ├── app.js
│   ├── home
│   │   ├── home.html
│   │   ├── controllers
│   │   │   ├── FirstCtrl.js
│   │   │   ├── FirstCtrl.spec.js
│   │   ├── directives
│   │   │   └── directive1.js
│   │   │   └── directive1.spec.js
│   │   ├── filters
│   │   │   ├── filter1.js
│   │   │   └── filter1.spec.js
│   │   └── services
│   │       ├── service1.js
│   │       └── service1.spec.js
│   └── about
│       ├── about.html
│       ├── controllers
│       │   └── ThirdCtrl.js
│       │   └── ThirdCtrl.spec.js
│       └── directives
│           ├── directive2.js
│           └── directive2.spec.js
├── partials
├── lib
└── e2e-tests
    ├── protractor.conf.js
    └── specs
        ├── home.js
        └── about.js

i18n

Performance

Contribution

Since the goal of this style guide is to be community-driven, contributions are greatly appreciated. For example, you can contribute by extending the Testing section or by translating the style guide to your language.

Contributors

<img alt="mgechev" src="https://avatars1.githubusercontent.com/u/455023?v=4&s=117" width="117"><img alt="morizotter" src="https://avatars1.githubusercontent.com/u/536954?v=4&s=117" width="117"><img alt="chatii2412" src="https://avatars2.githubusercontent.com/u/3435149?v=4&s=117" width="117"><img alt="pascalockert" src="https://avatars0.githubusercontent.com/u/4253438?v=4&s=117" width="117"><img alt="yanivefraim" src="https://avatars3.githubusercontent.com/u/1336186?v=4&s=117" width="117"><img alt="ericguirbal" src="https://avatars1.githubusercontent.com/u/322135?v=4&s=117" width="117">
mgechevmorizotterchatii2412pascalockertyanivefraimericguirbal
<img alt="agnislav" src="https://avatars2.githubusercontent.com/u/364255?v=4&s=117" width="117"><img alt="ray7551" src="https://avatars0.githubusercontent.com/u/1812388?v=4&s=117" width="117"><img alt="mainyaa" src="https://avatars0.githubusercontent.com/u/800781?v=4&s=117" width="117"><img alt="LeonardCModoran" src="https://avatars1.githubusercontent.com/u/8460505?v=4&s=117" width="117"><img alt="elfinxx" src="https://avatars2.githubusercontent.com/u/4384908?v=4&s=117" width="117"><img alt="tiagobarreto" src="https://avatars3.githubusercontent.com/u/45082?v=4&s=117" width="117">
agnislavray7551mainyaaLeonardCModoranelfinxxtiagobarreto
<img alt="Xuefeng-Zhu" src="https://avatars0.githubusercontent.com/u/5875315?v=4&s=117" width="117"><img alt="SullyP" src="https://avatars2.githubusercontent.com/u/12484363?v=4&s=117" width="117"><img alt="giacomocusinato" src="https://avatars0.githubusercontent.com/u/7659518?v=4&s=117" width="117"><img alt="rubystream" src="https://avatars3.githubusercontent.com/u/3200?v=4&s=117" width="117"><img alt="lukaszklis" src="https://avatars0.githubusercontent.com/u/11782?v=4&s=117" width="117"><img alt="Spuffynism" src="https://avatars2.githubusercontent.com/u/8978908?v=4&s=117" width="117">
Xuefeng-ZhuSullyPgiacomocusinatorubystreamlukaszklisSpuffynism
<img alt="susieyy" src="https://avatars0.githubusercontent.com/u/62295?v=4&s=117" width="117"><img alt="cironunes" src="https://avatars2.githubusercontent.com/u/469908?v=4&s=117" width="117"><img alt="cavarzan" src="https://avatars2.githubusercontent.com/u/3915288?v=4&s=117" width="117"><img alt="guiltry" src="https://avatars3.githubusercontent.com/u/1484308?v=4&s=117" width="117"><img alt="MSafter" src="https://avatars3.githubusercontent.com/u/5517637?v=4&s=117" width="117"><img alt="mingchen" src="https://avatars2.githubusercontent.com/u/1002838?v=4&s=117" width="117">
susieyycironunescavarzanguiltryMSaftermingchen
<img alt="jmblog" src="https://avatars0.githubusercontent.com/u/86085?v=4&s=117" width="117"><img alt="luixaviles" src="https://avatars0.githubusercontent.com/u/3485075?v=4&s=117" width="117"><img alt="andreasonny83" src="https://avatars0.githubusercontent.com/u/8806300?v=4&s=117" width="117"><img alt="kuzzmi" src="https://avatars3.githubusercontent.com/u/1727140?v=4&s=117" width="117"><img alt="jabhishek" src="https://avatars3.githubusercontent.com/u/1830537?v=4&s=117" width="117"><img alt="adambabik" src="https://avatars1.githubusercontent.com/u/277870?v=4&s=117" width="117">
jmblogluixavilesandreasonny83kuzzmijabhishekadambabik
<img alt="astalker" src="https://avatars0.githubusercontent.com/u/1486567?v=4&s=117" width="117"><img alt="clbn" src="https://avatars1.githubusercontent.com/u/1071933?v=4&s=117" width="117"><img alt="atodorov" src="https://avatars3.githubusercontent.com/u/1002300?v=4&s=117" width="117"><img alt="apetro" src="https://avatars3.githubusercontent.com/u/952283?v=4&s=117" width="117"><img alt="valgreens" src="https://avatars2.githubusercontent.com/u/903263?v=4&s=117" width="117"><img alt="bitdeli-chef" src="https://avatars2.githubusercontent.com/u/3092978?v=4&s=117" width="117">
astalkerclbnatodorovapetrovalgreensbitdeli-chef
<img alt="meetbryce" src="https://avatars1.githubusercontent.com/u/1845143?v=4&s=117" width="117"><img alt="unseen1980" src="https://avatars1.githubusercontent.com/u/2386570?v=4&s=117" width="117"><img alt="cminhho" src="https://avatars3.githubusercontent.com/u/10251630?v=4&s=117" width="117"><img alt="dwmkerr" src="https://avatars2.githubusercontent.com/u/1926984?v=4&s=117" width="117"><img alt="kuzmeig1" src="https://avatars2.githubusercontent.com/u/8707951?v=4&s=117" width="117"><img alt="dominickolbe" src="https://avatars0.githubusercontent.com/u/6094725?v=4&s=117" width="117">
meetbryceunseen1980cminhhodwmkerrkuzmeig1dominickolbe
<img alt="gsamokovarov" src="https://avatars0.githubusercontent.com/u/604618?v=4&s=117" width="117"><img alt="grvcoelho" src="https://avatars3.githubusercontent.com/u/7416751?v=4&s=117" width="117"><img alt="yassirh" src="https://avatars2.githubusercontent.com/u/4649139?v=4&s=117" width="117"><img alt="bargaorobalo" src="https://avatars1.githubusercontent.com/u/993001?v=4&s=117" width="117"><img alt="hermankan" src="https://avatars2.githubusercontent.com/u/2899106?v=4&s=117" width="117"><img alt="jesselpalmer" src="https://avatars1.githubusercontent.com/u/682097?v=4&s=117" width="117">
gsamokovarovgrvcoelhoyassirhbargaorobalohermankanjesselpalmer
<img alt="capaj" src="https://avatars0.githubusercontent.com/u/1305378?v=4&s=117" width="117"><img alt="johnnyghost" src="https://avatars0.githubusercontent.com/u/1117330?v=4&s=117" width="117"><img alt="jordanyee" src="https://avatars3.githubusercontent.com/u/3303098?v=4&s=117" width="117"><img alt="whoan" src="https://avatars1.githubusercontent.com/u/7103003?v=4&s=117" width="117"><img alt="nacyot" src="https://avatars3.githubusercontent.com/u/148919?v=4&s=117" width="117"><img alt="mariolamacchia" src="https://avatars1.githubusercontent.com/u/6282722?v=4&s=117" width="117">
capajjohnnyghostjordanyeewhoannacyotmariolamacchia
<img alt="mischkl" src="https://avatars2.githubusercontent.com/u/8177979?v=4&s=117" width="117"><img alt="michaelmov" src="https://avatars1.githubusercontent.com/u/4242002?v=4&s=117" width="117"><img alt="kirstein" src="https://avatars1.githubusercontent.com/u/426442?v=4&s=117" width="117"><img alt="mo-gr" src="https://avatars2.githubusercontent.com/u/95577?v=4&s=117" width="117"><img alt="mortonfox" src="https://avatars1.githubusercontent.com/u/495892?v=4&s=117" width="117"><img alt="cryptojuice" src="https://avatars1.githubusercontent.com/u/458883?v=4&s=117" width="117">
mischklmichaelmovkirsteinmo-grmortonfoxcryptojuice
<img alt="nktssh" src="https://avatars1.githubusercontent.com/u/1872256?v=4&s=117" width="117"><img alt="olafahn" src="https://avatars3.githubusercontent.com/u/7765194?v=4&s=117" width="117"><img alt="olov" src="https://avatars1.githubusercontent.com/u/19247?v=4&s=117" width="117"><img alt="vorktanamobay" src="https://avatars2.githubusercontent.com/u/2623355?v=4&s=117" width="117"><img alt="QuietHeartThinkingFar" src="https://avatars2.githubusercontent.com/u/13879579?v=4&s=117" width="117"><img alt="raphaelfruneaux" src="https://avatars3.githubusercontent.com/u/3259312?v=4&s=117" width="117">
nktssholafahnolovvorktanamobayQuietHeartThinkingFarraphaelfruneaux
<img alt="sahat" src="https://avatars1.githubusercontent.com/u/544954?v=4&s=117" width="117"><img alt="ganchiku" src="https://avatars1.githubusercontent.com/u/149973?v=4&s=117" width="117"><img alt="kaneshin" src="https://avatars0.githubusercontent.com/u/936972?v=4&s=117" width="117"><img alt="imaimiami" src="https://avatars1.githubusercontent.com/u/2256037?v=4&s=117" width="117"><img alt="dooart" src="https://avatars3.githubusercontent.com/u/371426?v=4&s=117" width="117"><img alt="thomastuts" src="https://avatars2.githubusercontent.com/u/1914255?v=4&s=117" width="117">
sahatganchikukaneshinimaimiamidooartthomastuts
<img alt="UrielMiranda" src="https://avatars2.githubusercontent.com/u/12901838?v=4&s=117" width="117"><img alt="vkarampinis" src="https://avatars1.githubusercontent.com/u/330736?v=4&s=117" width="117"><img alt="grapswiz" src="https://avatars2.githubusercontent.com/u/309459?v=4&s=117" width="117"><img alt="coderhaoxin" src="https://avatars2.githubusercontent.com/u/2569835?v=4&s=117" width="117"><img alt="giantray" src="https://avatars1.githubusercontent.com/u/5054377?v=4&s=117" width="117"><img alt="ntaoo" src="https://avatars2.githubusercontent.com/u/511213?v=4&s=117" width="117">
UrielMirandavkarampinisgrapswizcoderhaoxingiantrayntaoo
<img alt="seyyah" src="https://avatars0.githubusercontent.com/u/263237?v=4&s=117" width="117"><img alt="dchest" src="https://avatars2.githubusercontent.com/u/52677?v=4&s=117" width="117">
seyyahdchest