• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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&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 */
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&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">
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>&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 */
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