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"> 78goog.provide('hello.about.AboutCtrl'); 79goog.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 */ 171hello.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 */ 188hello.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<div ng-controller="hello.mainpage.HomeCtrl"/> 197 <span ng-class="homeCtrl.myColor">I'm in a color!</span> 198 <span>{{homeCtrl.add(5, 6)}}</span> 199</div> 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 */ 212hello.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 */ 226hello.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<div ng-controller="hello.mainpage.HomeCtrl as homeCtrl"/> 238 <span ng-class="homeCtrl.myColor">I'm in a color!</span> 239 <span>{{homeCtrl.add(5, 6)}}</span> 240</div> 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"> 257goog.provide('hello.pane.paneDirective'); 258 259/** 260 * Description and usage 261 * @return {angular.Directive} Directive definition object. 262 */ 263hello.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 */ 283hello.request.Request = function($http) { 284 /** @type {!angular.$http} */ 285 this.http_ = $http; 286}; 287 288hello.request.Request.prototype.get = function() {/*...*/}; 289</pre> 290 291<p>In the module:</p> 292 293<pre class="prettyprint lang-js"> 294module.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><ng-include src="template"></ng-include></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 */ 376my.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