Home | History | Annotate | Download | only in google-styleguide
      1 
      2 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "https://www.w3.org/TR/REC-html40/strict.dtd">
      3 <html>
      4 <head>
      5     <META http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
      6     <base target="_blank">
      7     <link rel="stylesheet" type="text/css" href="styleguide.css">
      8     <script src="https://google-code-prettify.googlecode.com/svn/loader/run_prettify.js"></script>
      9     <script language="javascript" src="/eng/doc/devguide/include/styleguide.js"></script>
     10     <title>Google's AngularJS Style Guide</title>
     11     <style type="text/css"><!--
     12     th { background-color: #ddd; }
     13     //--></style>
     14 </head>
     15 <body onload="prettyPrint();initStyleGuide();">
     16 <h1 class="external">An AngularJS Style Guide for Closure Users at Google</h1>
     17 
     18 <p class="external">This is the external version of a document that was primarily written for Google
     19     engineers. It describes a recommended style for AngularJS apps that use Closure, as used
     20     internally at Google. Members of the broader AngularJS community should feel free to apply
     21     (or not apply) these recommendations, as relevant to their own use cases.</p>
     22 
     23 <p class="external">This document describes style for AngularJS apps in google3. This guide
     24     supplements and extends the <a href="https://google.github.io/styleguide/jsguide.html">
     25         Google JavaScript Style Guide</a>.
     26 </p>
     27 
     28 <p><b>Style Note</b>: Examples on the AngularJS external webpage, and many external apps, are
     29     written in a style that freely uses closures, favors functional inheritance, and does not often use
     30     <a class="external"
     31                                href="https://github.com/google/closure-compiler/wiki/Types-in-the-Closure-Type-System">
     32         JavaScript types</a>. Google follows a more rigorous Javascript style to support JSCompiler
     33     optimizations and large code bases - see the javascript-style mailing list.
     34     This is not an Angular-specific issue, and is not discussed further in this style guide.
     35     (But if you want further reading:
     36     <a  href="http://martinfowler.com/bliki/Lambda.html">Martin Fowler on closures</a>,
     37     <a href="http://jibbering.com/faq/notes/closures/">much longer description</a>, appendix A of the
     38     <a href="https://books.google.com/books/about/Closure_The_Definitive_Guide.html?id=p7uyWPcVGZsC">
     39         closure book</a> has a good description of inheritance patterns and why it prefers
     40     pseudoclassical,
     41     <a href="https://books.google.com/books/about/JavaScript.html?id=PXa2bby0oQ0C">
     42         Javascript, the Good Parts</a> as a counter.)</p>
     43 
     44 <h5>1 Angular Language Rules</h5>
     45 <ul>
     46     <li> <a target="_self" href="#googprovide">Manage dependencies with Closure's goog.require and
     47         goog.provide</a>
     48     <li> <a target="_self" href="#modules"> Modules</a>
     49     <li> <a target="_self" href="#moduledeps"> Modules should reference other modules using the
     50         "name" property</a>
     51     <li> <a target="_self" href="#externs">Use the provided Angular externs file</a>
     52     <li> <a target="_self" href="#compilerflags">JSCompiler Flags</a>
     53     <li> <a target="_self" href="#controllers">Controllers and Scopes</a>
     54     <li> <a target="_self" href="#directives">Directives</a>
     55     <li> <a target="_self" href="#services">Services</a>
     56 </ul>
     57 <h5>2 Angular Style Rules</h5>
     58 <ul>
     59     <li><a target="_self" href="#dollarsign">Reserve $ for Angular properties and services
     60     </a>
     61     <li><a target="_self" href="#customelements">Custom elements.</a>
     62 </ul>
     63 <h5>3 Angular Tips, Tricks, and Best Practices</h5>
     64 <ul>
     65     <li><a target="_self" href="#testing">Testing</a>
     66     <li><a target="_self" href="#appstructure">Consider using the Best Practices for App Structure</a>
     67     <li><a target="_self" href="#scopeinheritance">Be aware of how scope inheritance works</a>
     68     <li><a target="_self" href="#nginject">Use @ngInject for easy dependency injection compilation</a>
     69 </ul>
     70 
     71 <h5><a target="_self" href="#bestpractices">4 Best practices links and docs</a></h5>
     72 
     73 <h2>1 Angular Language Rules</h2>
     74 
     75 <h3 id="googprovide">Manage dependencies with Closure's goog.require and goog.provide</h3>
     76 <p>Choose a namespace for your project, and use goog.provide and goog.require.</p>
     77 <pre class="prettyprint lang-js">
     78 goog.provide('hello.about.AboutCtrl');
     79 goog.provide('hello.versions.Versions');
     80 </pre>
     81 
     82 <p><b>Why?</b>
     83     Google BUILD rules integrate nicely with closure provide/require.</p>
     84 
     85 <h3 id="modules">Modules</h3>
     86 
     87 <p>Your main application module should be in your root client directory. A module should never be
     88     altered other than the one where it is defined.</p>
     89 
     90 <p>Modules may either be defined in the same file as their components (this works well for a module
     91     that contains exactly one service) or in a separate file for wiring pieces together.</p>
     92 
     93 <p><b>Why?</b>
     94     A module should be consistent for anyone that wants to include it as a reusable component.
     95     If a module can mean different things depending on which files are included, it is not consistent.
     96 </p>
     97 
     98 <h3 id="moduledeps">
     99     Modules should reference other modules using the Angular Module's "name" property
    100 </h3>
    101 
    102 <p>For example:</p>
    103 
    104 <pre class="prettyprint lang-js">
    105 // file submodulea.js:
    106   goog.provide('my.submoduleA');
    107 
    108   my.submoduleA = angular.module('my.submoduleA', []);
    109   // ...
    110 
    111 // file app.js
    112   goog.require('my.submoduleA');
    113 
    114   Yes: my.application.module = angular.module('hello', [my.submoduleA.name]);
    115   <font color="red">
    116       No: my.application.module = angular.module('hello', ['my.submoduleA']);
    117   </font></pre>
    118 
    119 <p><b>Why?</b>
    120     Using a property of my.submoduleA prevents Closure presubmit failures complaining that the file is
    121     required but never used. Using the .name property avoids duplicating strings.</p>
    122 
    123 <h3 id="externs">Use a common externs file</h3>
    124 
    125 <p>This maximally allows the JS compiler to enforce type safety in the presence of externally
    126     provided types from Angular, and means you don't have to worry about Angular vars being obfuscated
    127     in a confusing way. </p>
    128 
    129 <p>Note to readers outside Google: the current externs file is located in an internal-to-Google
    130     directory, but an example can be found on github <a href="https://github.com/angular/angular.js/pull/4722">
    131         here</a>.</p>
    132 
    133 <h3 id="compilerflags">JSCompiler Flags</h3>
    134 <p><b>Reminder</b>: According to the JS style guide, customer facing code must be compiled.</p>
    135 
    136 <p><b>Recommended</b>: Use the JSCompiler (the closure compiler that works with js_binary by
    137     default) and ANGULAR_COMPILER_FLAGS_FULL from //javascript/angular/build_defs/build_defs for
    138     your base flags.
    139 </p>
    140 
    141 <p>Note - if you are using @export for methods, you will need to add the compiler flag</p>
    142 <pre>
    143 "--generate_exports",
    144 </pre>
    145 
    146 <p>If you are using @export for properties, you will need to add the flags:</p>
    147 <pre>
    148 "--generate_exports",
    149 "--remove_unused_prototype_props_in_externs=false",
    150 "--export_local_property_definitions",
    151 </pre>
    152 
    153 <h3 id="controllers">Controllers and Scopes</h3>
    154 <p>Controllers are classes. Methods should be defined on MyCtrl.prototype.</p>
    155 
    156 <p>Google Angular applications should use the <b>'controller as'</b> style to export the controller
    157     onto the scope. This is fully implemented in Angular 1.2 and can be mimicked in pre-Angular 1.2
    158     builds.
    159 </p>
    160 
    161 <p>Pre Angular 1.2, this looks like:</p>
    162 <pre class="prettyprint lang-js">
    163 /**
    164  * Home controller.
    165  *
    166  * @param {!angular.Scope} $scope
    167  * @constructor
    168  * @ngInject
    169  * @export
    170  */
    171 hello.mainpage.HomeCtrl = function($scope) {
    172   /** @export */
    173   $scope.homeCtrl = this; // This is a bridge until Angular 1.2 controller-as
    174 
    175   /**
    176    * @type {string}
    177    * @export
    178    */
    179   this.myColor = 'blue';
    180 };
    181 
    182 
    183 /**
    184  * @param {number} a
    185  * @param {number} b
    186  * @export
    187  */
    188 hello.mainpage.HomeCtrl.prototype.add = function(a, b) {
    189   return a + b;
    190 };
    191 </pre>
    192 
    193 <p>And the template:</p>
    194 
    195 <pre>
    196 &lt;div ng-controller="hello.mainpage.HomeCtrl"/&gt;
    197   &lt;span ng-class="homeCtrl.myColor"&gt;I'm in a color!&lt;/span&gt;
    198   &lt;span&gt;{{homeCtrl.add(5, 6)}}&lt;/span&gt;
    199 &lt;/div&gt;
    200 </pre>
    201 
    202 <p>After Angular 1.2, this looks like:</p>
    203 
    204 <pre class="prettyprint lang-js">
    205 /**
    206  * Home controller.
    207  *
    208  * @constructor
    209  * @ngInject
    210  * @export
    211  */
    212 hello.mainpage.HomeCtrl = function() {
    213   /**
    214    * @type {string}
    215    * @export
    216    */
    217   this.myColor = 'blue';
    218 };
    219 
    220 
    221 /**
    222  * @param {number} a
    223  * @param {number} b
    224  * @export
    225  */
    226 hello.mainpage.HomeCtrl.prototype.add = function(a, b) {
    227   return a + b;
    228 };
    229 </pre>
    230 
    231 <p>If you are compiling with property renaming, expose properties and methods using the @export
    232     annotation. Remember to @export the constructor as well.</p>
    233 
    234 <p>And in the template:</p>
    235 
    236 <pre>
    237 &lt;div ng-controller="hello.mainpage.HomeCtrl as homeCtrl"/&gt;
    238   &lt;span ng-class="homeCtrl.myColor"&gt;I'm in a color!&lt;/span&gt;
    239   &lt;span&gt;{{homeCtrl.add(5, 6)}}&lt;/span&gt;
    240 &lt;/div&gt;
    241 </pre>
    242 
    243 <p><b>Why?</b>
    244     Putting methods and properties directly onto the controller, instead of building up a scope
    245     object, fits better with the Google Closure class style. Additionally, using 'controller as'
    246     makes it obvious which controller you are accessing when multiple controllers apply to an element.
    247     Since there is always a '.' in the bindings, you don't have to worry about prototypal inheritance
    248     masking primitives.</p>
    249 
    250 <h3 id="directives">Directives</h3>
    251 
    252 <p>All DOM manipulation should be done inside directives. Directives should be kept small and use
    253     composition. Files defining directives should goog.provide a static function which returns the
    254     directive definition object.</p>
    255 
    256 <pre class="prettyprint lang-js">
    257 goog.provide('hello.pane.paneDirective');
    258 
    259 /**
    260  * Description and usage
    261  * @return {angular.Directive} Directive definition object.
    262  */
    263 hello.pane.paneDirective = function() {
    264   // ...
    265 };
    266 </pre>
    267 
    268 <p><b>Exception</b>: DOM manipulation may occur in services for DOM elements disconnected from the
    269     rest of the view, e.g. dialogs or keyboard shortcuts.</p>
    270 
    271 <h3 id="services">Services</h3>
    272 
    273 <p>Services registered on the module with <code>module.service</code> are classes.
    274     Use <code>module.service</code> instead of <code>module.provider</code> or
    275     <code>module.factory</code> unless you need to do initialization beyond just creating a
    276     new instance of the class.</p>
    277 
    278 <pre class="prettyprint lang-js">
    279 /**
    280  * @param {!angular.$http} $http The Angular http service.
    281  * @constructor
    282  */
    283 hello.request.Request = function($http) {
    284   /** @type {!angular.$http} */
    285   this.http_ = $http;
    286 };
    287 
    288 hello.request.Request.prototype.get = function() {/*...*/};
    289 </pre>
    290 
    291 <p>In the module:</p>
    292 
    293 <pre class="prettyprint lang-js">
    294 module.service('request', hello.request.Request);
    295 </pre>
    296 
    297 
    298 <h2>2 Angular Style Rules</h2>
    299 
    300 <h3 id="dollarsign">Reserve $ for Angular properties and services</h3>
    301 <p>Do not use $ to prepend your own object properties and service identifiers. Consider this style
    302     of naming reserved by AngularJS and jQuery.</p>
    303 
    304 <p>Yes:</p>
    305 <pre class="prettyprint lang-js">
    306   $scope.myModel = { value: 'foo' }
    307   myModule.service('myService', function() { /*...*/ });
    308   var MyCtrl = function($http) {this.http_ = $http;};
    309 </pre>
    310 
    311 <p><font color="red">No:</font></p>
    312 <pre class="prettyprint">
    313   $scope.$myModel = { value: 'foo' } // BAD
    314   $scope.myModel = { $value: 'foo' } // BAD
    315   myModule.service('$myService', function() { ... }); // BAD
    316   var MyCtrl = function($http) {this.$http_ = $http;}; // BAD
    317 </pre>
    318 
    319 <p><b>Why?</b>
    320     It's useful to distinguish between Angular / jQuery builtins and things you add yourself.
    321     In addition, $ is not an acceptable character for variables names in the JS style guide.
    322 </p>
    323 
    324 <h3 id="customelements">Custom elements</h3>
    325 
    326 <p>For custom elements (e.g. <code>&lt;ng-include src="template"&gt;&lt;/ng-include&gt;</code>), IE8
    327     requires special support (html5shiv-like hacks) to enable css styling.  Be aware of this
    328     restriction in apps targeting old versions of IE.</p>
    329 
    330 <h2>3 Angular Tips, Tricks, and Best Practices</h2>
    331 
    332 <p>These are not strict style guide rules, but are placed here as reference for folks getting
    333     started with Angular at Google.</p>
    334 
    335 <h3 id="testing">Testing</h3>
    336 
    337 <p>Angular is designed for test-driven development.</p>
    338 
    339 <p>The recommended unit testing setup is Jasmine + Karma (though you could use closure tests
    340     or js_test)</p>
    341 
    342 <p>Angular provides easy adapters to load modules and use the injector in Jasmine tests.
    343 <ul>
    344     <li><a href = "https://docs.angularjs.org/api/angular.mock.module">module</a>
    345     <li><a href="https://docs.angularjs.org/api/angular.mock.inject">inject</a>
    346 </ul>
    347 </p>
    348 
    349 
    350 <h3 id="appstructure">Consider using the Best Practices for App Structure</h3>
    351 <p>
    352     This  <a href="https://docs.google.com/document/d/1XXMvReO8-Awi1EZXAXS4PzDzdNvV6pGcuaF4Q9821Es/pub">directory structure doc</a> describes how to structure your application with controllers in
    353     nested subdirectories and all components (e.g. services and directives) in a 'components' dir.
    354 </p>
    355 
    356 
    357 <h3 id="scopeinheritance">Be aware of how scope inheritance works</h3>
    358 
    359 <p>See <a href="https://github.com/angular/angular.js/wiki/Understanding-Scopes#wiki-JSproto">
    360     The Nuances of Scope Prototypal Inheritance</a></p>
    361 
    362 <h3 id="nginject">Use @ngInject for easy dependency injection compilation</h3>
    363 <p>This removes the need to add <code>myCtrl['$inject'] = ...</code> to prevent minification from
    364     messing up Angular's dependency injection.</p>
    365 
    366 <p>Usage:</p>
    367 <pre class="prettyprint lang-js">
    368 /**
    369  * My controller.
    370  * @param {!angular.$http} $http
    371  * @param {!my.app.myService} myService
    372  * @constructor
    373  * @export
    374  * @ngInject
    375  */
    376 my.app.MyCtrl = function($http, myService) {
    377   //...
    378 };
    379 </pre>
    380 
    381 <h2 id="bestpractices">4 Best practices links and docs</h2>
    382 
    383 <ul>
    384     <li><a href="https://github.com/angular/angular.js/wiki/Best-Practices">
    385         Best Practices</a> from Angular on GitHub</li>
    386     <li><a href="https://www.youtube.com/watch?v=ZhfUv0spHCY">
    387         Meetup video</a> (not Google specific)</li>
    388 </ul>
    389 <address>
    390     Last modified Feb 07 2013
    391 </address>
    392 </body>
    393 <html>
    394