Coding Standards (AngularJS)
Coding Standards (AngularJS)
India Engineering
Document Approval
Revision History
Index
General Information
Coding Standard Guideline for AngularJS / JQuery would help to write reliable, maintainable and
efficient code to deliver best quality software.
The naming conventions, coding standards and best practices described in this document are compiled
from our own experience and by referring to various Microsoft and non-Microsoft guidelines.
Use semicolons ;
Commas last ,
2 spaces for indentation (no tabs)
Prefer ' over "
'use strict';
80 character line length
Write "attractive" code
JavaScript
Use Strict.
Define one component per file
Refer to your normal JavaScript coding guidelines
Apply basic programming techniques
[SOLID] (http://en.wikipedia.org/wiki/SOLID_(object-oriented_design))
DRY
KISS
YAGNI
Comment your code
Consider using lodash and functional styles
Naming
Do not name your modules/variables with the $ prefix or $$, that is for core components.
Do not prefix your directives or controller with ng- or ui- or elsewhere.
Use CamelCase.
Append the controller name with the suffix Controller or with no suffix. Choose 1, not both.
Use short custom prefixes for your directives to prevent name collisions with third-party
libraries.
Use consistent names for all components following a pattern that describes the components
feature then (optionally) its type. e.g. feature.type.js
// Controllers
avengers.js
avengers.controller.js
Johnson Controls – Confidential Page 3 of 11
Coding Standards for AngularJS/JQuery
India Engineering
avengersController.js
// Services/Factories
logger.js
logger.service.js
loggerService.js
Name test specifications similar to the component they test with a suffix of spec
avengers.controller.spec.js
logger.service.spec.js
avengers.routes.spec.js
avenger-profile.directive.spec.js
When there are multiple modules, the main module file is named app.module.js while other
dependent modules are named after what they represent. For example, an admin module is
named admin.module.js. The respective registered module names would be app and admin. A
single module app might be named app.js, omitting the module moniker.
Constants
Vendor Globals: Create an AngularJS Constant for vendor libraries' global variables.
// constants.js
/* global toastr:false, moment:false */
(function() {
'use strict';
angular
.module('app.core')
.constant('toastr', toastr)
.constant('moment', moment);
})();
Markup
Put scripts at the bottom of your HTML
Put Angular attributes at the end of element declarations
Use folders for modules rather than splitting on class type (directive/controller/model)
|-- app.js
|-- dashboard/
| |-- DashboardService.js
| |-- DashboardCtrl.js
Johnson Controls – Confidential Page 4 of 11
Coding Standards for AngularJS/JQuery
India Engineering
|-- login/
| |-- LoginService.js
| |-- LoginCtrl.js
|-- inbox/
| |-- InboxService.js
| |-- InboxCtrl.js
Modules
Use multiple modules. Do not put everything into the main controller or module.
Keep the App Module Thin: Only put logic for pulling together the app in the application
module. Leave features in their own modules
Create modules that represent feature areas, such as layout, reusable and shared services,
dashboards, and app specific features. (Avoid Naming Collisions: Use unique naming
conventions with separators for sub-modules.)
Create modules that represent reusable application blocks for common services such as
exception handling, logging, diagnostics, security, and local data stashing.
Add services and controllers to a module and then add the module to the app.
Use named functions instead of passing an anonymous function in as a callback.
// dashboard.js
angular
.module('app')
.controller('Dashboard', Dashboard);
'use strict';
module.exports = function($scope) {
$scope.foo = 'bar';
…
};
*Only set a module once and get for all other instances.
Global Dependencies
Encapsulate globals into a module so that they can be injected.
Bindings
For content that is only loaded once consider using bind once.
Avoid too many watchers. Make computation in any watchers as simple as possible.
Set the third parameter in $timeout to false when no watched variables are impacted to avoid
the $digest cycle.
Controllers
Never do DOM manipulation in a controller.
Business logic should live in services and not in controllers.
Use routing instead of binding a controller directly to the DOM.
angular
.module('app')
.config(config);
function config($routeProvider) {
$routeProvider
.when('/avengers', {
templateUrl: 'avengers.html',
controller: 'Avengers',
controllerAs: 'vm'
});
}
Controllers should not be defined as globals.
Place bindable members at the top of the controller.
Use function declarations to hide implementation details.
function Order(creditService) {
var vm = this;
vm.checkCredit = checkCredit;
vm.total = 0;
function checkCredit() {
return creditService.check();
};
}
Use the controllerAs syntax over the classic controller with $scope syntax.
Directives
DOM manipulation should be done in the link method.
One directive per file.
Restrict to elements and attributes
Use scope instead of $scope in your link function. In the compile, post/pre link functions you
have already defined arguments which will be passed when the function is invoked, you won't
be able to change them using DI. This style is also used in AngularJS's source code.
Create an isolated scope when you develop reusable components.
Use directives as attributes or elements instead of comments or classes, this will make your
code more readable.
Use $scope.$on('$destroy', fn) for cleaning up. This is especially useful when you're wrapping
third-party plugins as directives.
Extend directives by using Directive Controllers: You can place methods and properties into a
directive-controller, and access that same controller from other directives. You can even
override methods and properties through this relationship
Do not forget to use $sce when you should deal with untrusted content.
Filters
Encapsulate formatting in Filters.
Make your filters as light as possible. They are called often during the $digest loop so creating a
slow filter will slow down your app.
Do a single thing in your filters, keep them coherent. More complex manipulations can be
achieved by piping existing filters.
Services/Factories
$timeout instead of setTimeout
$interval instead of setInterval
$window instead of window
$document instead of document
$http instead of $.ajax
Use promises ($q) instead of callbacks
$resource instead of $http whenever possible
For session-level cache you can use $cacheFactory. This should be used to cache results from
requests or heavy computations.
If given service requires configuration define the service as provider and configure it in the
configcallback like:
Factories should have a single responsibility
Accessible members should be at the top
Use function declarations to hide implementation detail
Data Services
Separate Data Calls: Refactor logic for making data operations and interacting with data to a
factory. Make data services responsible for XHR calls, local storage, stashing in memory, or any
other data operations.
Return a Promise from Data Calls: When calling a data service that returns a promise such as
$http, return a promise in your calling function too.
Templates
Use ng-bind or ng-cloak instead of simple {{ }} to prevent flashing content.
Avoid writing complex expressions in the templates.
When you need to set the src of an image dynamically use ng-src instead of src with {{
}}template.
When you need to set the href of an anchor tag dynamically use ng-href instead of href with{{ }}
template.
Instead of using scope variable as string and using it with style attribute with {{ }}, use the
directive ng-style with object-like parameters and scope variables as values:
Routing
Use Batarang
Learn to use the Chrome extension to debug you apps. In particular note the Angular tab on
the elements view when you inspect an element – it will show the bound scope and its
contents!
Scopes
Be aware that scopes inherit from the parent scope. Watch out for shadowing of variables.
Directives on the other hand isolate scope and only inherit explicitly declared properties.
Avoid $scope.$watch where possible, or unless unavoidable.
Exception Handling
Exception Catchers: Create a factory that exposes an interface to catch and gracefully handle
exceptions.
angular
.module('blocks.exception')
.factory('exception', exception);
exception.$inject = ['logger'];
function exception(logger) {
var service = {
catcher: catcher
};
return service;
function catcher(message) {
return function(reason) {
logger.error(message, reason);
};
}
}
Route Errors: Handle and log all routing errors using $routeChangeError.
function handleRoutingErrors() {
/**
* Route cancellation:
* On routing error, go to the dashboard.
* Provide an exit clause if it tries to do it twice.
*/
$rootScope.$on('$routeChangeError',
function(event, current, previous, rejection) {
var destination = (current && (current.title || current.name ||
current.loadedTemplateUrl)) ||
'unknown target';
var msg = 'Error routing to ' + destination + '. ' +
(rejection.msg || '');
/**
* Optionally log using a custom service or $log.
* (Don't forget to inject custom service)
*/
logger.warning(msg, [current]);
}
);
}
decorators: Use a decorator, at config time using the $provide service, on the
$exceptionHandler service to perform custom actions when exceptions occur.
Broadcast Messages
Avoid broadcasting messages/events on the $rootscope. Instead create a custom service for each
event you want to broadcast.
.service("hiEventService",function($rootScope) {
this.broadcast = function() {$rootScope.$broadcast("hi")}
this.listen = function(callback) {$rootScope.$on("hi",callback)}
})
Testing
Angular has built-in support for testing, see ngMock, Jasmine, Protractor and Karma.
JQuery