angularjs-style-guide
📚 Community-driven set of best practices for AngularJS application development
Top Related Projects
Angular Style Guide: A starting point for Angular development teams to provide consistency through good practices.
AngularJS styleguide for teams
Deliver web apps with confidence 🚀
AngularJS - HTML enhanced for web apps!
JavaScript Style Guide
Clean Code concepts adapted for JavaScript
Quick Overview
The mgechev/angularjs-style-guide is a comprehensive style guide for AngularJS applications. It provides best practices, conventions, and recommendations for writing clean, maintainable, and efficient AngularJS code. The guide covers various aspects of AngularJS development, including project structure, naming conventions, and coding patterns.
Pros
- Offers a detailed and well-organized set of guidelines for AngularJS development
- Helps maintain consistency across large-scale AngularJS projects
- Includes community-driven best practices and recommendations
- Provides examples and explanations for each guideline
Cons
- Focused on AngularJS (1.x), which is now considered legacy compared to Angular (2+)
- May require updates to stay relevant with modern web development practices
- Some guidelines may be opinionated and not universally accepted
Code Examples
This is not a code library, so code examples are not applicable.
Getting Started
As this is a style guide and not a code library, there are no specific getting started instructions. However, developers can start using the guide by following these steps:
- Visit the GitHub repository: https://github.com/mgechev/angularjs-style-guide
- Read through the README.md file for an overview of the guide
- Navigate through the different sections of the guide to find relevant recommendations
- Implement the guidelines in your AngularJS projects
- Consider contributing to the guide by submitting pull requests or issues for improvements or updates
Competitor Comparisons
Angular Style Guide: A starting point for Angular development teams to provide consistency through good practices.
Pros of angular-styleguide
- More comprehensive coverage of Angular concepts and best practices
- Includes detailed explanations and rationale for each guideline
- Offers visual examples and diagrams to illustrate concepts
Cons of angular-styleguide
- May be overwhelming for beginners due to its extensive content
- Some guidelines might be considered opinionated or subjective
- Requires more frequent updates to stay current with Angular's rapid evolution
Code Comparison
angularjs-style-guide:
angular
.module('app', ['ngRoute'])
.controller('SomeController', SomeController);
function SomeController() { }
angular-styleguide:
angular
.module('app')
.controller('SomeController', SomeController);
SomeController.$inject = ['$log', 'dataService'];
function SomeController($log, dataService) { }
The angular-styleguide example demonstrates explicit dependency injection, which is recommended for better minification support and clearer code structure. It also separates the controller function definition from the module declaration, promoting better organization and readability.
Both style guides aim to improve code quality and maintainability in Angular applications, but they differ in their approach and level of detail. The choice between them often depends on team preferences and project requirements.
AngularJS styleguide for teams
Pros of angularjs-styleguide
- More comprehensive and detailed guidelines
- Includes sections on testing and performance optimization
- Provides examples of both good and bad practices
Cons of angularjs-styleguide
- Less frequently updated compared to angularjs-style-guide
- Focuses primarily on AngularJS 1.x, with limited coverage of newer versions
- Some sections may be outdated due to changes in Angular ecosystem
Code Comparison
angularjs-styleguide:
// Recommended
function MainCtrl (SomeService) {
this.doSomething = function () {
SomeService.doSomething();
};
}
angular.module('app').controller('MainCtrl', MainCtrl);
angularjs-style-guide:
// Recommended
function MainController(someService) {
var vm = this;
vm.doSomething = doSomething;
function doSomething() {
someService.doSomething();
}
}
Both guides promote similar best practices, but angularjs-styleguide tends to be more concise and focused on modern Angular development. The code examples show slight differences in naming conventions and function organization, with angularjs-style-guide favoring the "vm" (ViewModel) approach. Overall, both guides offer valuable insights for Angular developers, with angularjs-style-guide being more up-to-date and angularjs-styleguide providing a broader range of topics.
Deliver web apps with confidence 🚀
Pros of Angular
- Official framework repository with full source code and documentation
- Actively maintained by Google and the community with frequent updates
- Comprehensive tooling and CLI support for development and testing
Cons of Angular
- Larger learning curve due to TypeScript and more complex architecture
- Heavier bundle size compared to AngularJS
- More opinionated structure, which may limit flexibility for some projects
Code Comparison
AngularJS Style Guide (Component):
angular.module('app').component('myComponent', {
templateUrl: 'my-component.html',
controller: MyComponentController,
bindings: {
data: '<'
}
});
Angular (Component):
@Component({
selector: 'app-my-component',
templateUrl: './my-component.component.html',
styleUrls: ['./my-component.component.css']
})
export class MyComponentComponent {
@Input() data: any;
}
Key Differences
- AngularJS Style Guide focuses on best practices for AngularJS 1.x
- Angular is a complete rewrite, using TypeScript and a component-based architecture
- Angular offers improved performance and better support for mobile development
- AngularJS Style Guide is a community-driven project, while Angular is officially maintained by Google
Use Cases
- AngularJS Style Guide: Ideal for maintaining existing AngularJS projects or learning best practices for AngularJS 1.x
- Angular: Recommended for new projects, large-scale applications, and teams looking for long-term support and modern web development features
AngularJS - HTML enhanced for web apps!
Pros of angular.js
- Official AngularJS repository with comprehensive documentation and examples
- Active community support and regular updates
- Contains the full AngularJS framework source code
Cons of angular.js
- Large codebase, which can be overwhelming for beginners
- Focuses on framework implementation rather than best practices
- Less emphasis on specific style guidelines
Code Comparison
angularjs-style-guide:
// Recommended
function MainCtrl (SomeService) {
this.doSomething = function () {
SomeService.doSomething();
};
}
angular.js:
// Example from angular.js
function $CompileProvider($provide, $$sanitizeUriProvider) {
var hasDirectives = {},
Suffix = 'Directive',
COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\w\-]+)\s+(.*)$/,
CLASS_DIRECTIVE_REGEXP = /(([\w\-]+)(?:\:([^;]+))?;?)/;
}
Summary
The angularjs-style-guide repository focuses on providing best practices and coding conventions for AngularJS development, while angular.js is the official framework repository. The style guide offers more concise and targeted guidance for developers, whereas angular.js provides the full framework implementation with extensive documentation. The style guide is better suited for learning and maintaining consistent coding practices, while angular.js is essential for understanding the framework's inner workings and contributing to its development.
JavaScript Style Guide
Pros of javascript
- More comprehensive, covering a wider range of JavaScript topics
- Regularly updated with modern JavaScript practices
- Widely adopted in the industry, making it a de facto standard
Cons of javascript
- Less focused on specific frameworks, potentially lacking depth in certain areas
- May be overwhelming for beginners due to its extensive coverage
- Some rules might be opinionated and not universally agreed upon
Code Comparison
angularjs-style-guide:
// Recommended
function setName(name) {
this.name = name;
}
// Avoid
function set_name(name) {
this.name = name;
}
javascript:
// Good
function getFullName(firstName, lastName) {
return `${firstName} ${lastName}`;
}
// Bad
const getFullName = function(firstName, lastName) {
return firstName + ' ' + lastName;
};
Summary
While angularjs-style-guide focuses specifically on AngularJS best practices, javascript provides a more comprehensive set of guidelines for JavaScript development in general. The latter is more widely adopted and regularly updated, but may lack depth in framework-specific areas. Both offer valuable insights, with javascript being more suitable for general JavaScript development and angularjs-style-guide being more appropriate for AngularJS-specific projects.
Clean Code concepts adapted for JavaScript
Pros of clean-code-javascript
- Covers a broader range of JavaScript best practices, not limited to a specific framework
- More up-to-date with modern JavaScript features and practices
- Includes practical examples for each principle, making it easier to understand and apply
Cons of clean-code-javascript
- Lacks specific guidance for AngularJS development
- May not address some of the unique challenges faced in AngularJS projects
- Less structured organization compared to the AngularJS style guide
Code Comparison
angularjs-style-guide:
angular
.module('app', [])
.controller('MainCtrl', MainCtrl);
function MainCtrl() {
var vm = this;
vm.title = 'Some Title';
}
clean-code-javascript:
class MainController {
constructor() {
this.title = 'Some Title';
}
}
export default MainController;
The clean-code-javascript example uses modern ES6 class syntax, while the angularjs-style-guide example follows AngularJS-specific conventions. The clean-code-javascript approach is more generic and applicable to various JavaScript projects, whereas the angularjs-style-guide focuses on AngularJS best practices.
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
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:
- AngularJS source code
- Source code or articles I've read
- 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:
- Google's JavaScript style guide
- Mozilla's JavaScript style guide
- Douglas Crockford's JavaScript style guide
- Airbnb JavaScript style guide
- 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
- German
- Spanish
- French
- Indonesian
- Italian
- Japanese
- Korean
- Polish
- Portuguese
- Russian
- Serbian
- Serbian lat
- Chinese
- Turkish
Table of content
- General
- Modules
- Controllers
- Directives
- Filters
- Services
- Templates
- Routing
- E2E Testing
- i18n
- Performance
- Contribution
- Contributors
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:
- Creating high-level divisions by component types and lower-level divisions by functionality.
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
- Creating high-level divisions by functionality and lower-level divisions by component types.
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
- In case the directory name contains multiple words, use lisp-case syntax:
app
âââ app.js
âââ my-complex-module
  âââ controllers
  âââ directives
  âââ filters
  âââ services
- Put all the files associated with the given directive (i.e. templates, CSS/SASS files, JavaScript) in a single folder. If you choose to use this style be consistent and use it everywhere along your project.
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.
- The unit tests for a given component (
*.spec.js
) should be located in the directory where the component is. This way when you make changes to a given component finding its test is easy. The tests also act as documentation and show use cases.
services
âââ cache
â  âââ cache1.js
â  âââ cache1.spec.js
âââ models
âââ model1.js
âââ model1.spec.js
- The
app.js
file should contain route definitions, configuration and/or manual bootstrap (if required). - Each JavaScript file should only hold a single component. The file should be named with the component's name.
- Use AngularJS project structure template like Yeoman, ng-boilerplate.
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:
Element | Naming style | Example | usage |
---|---|---|---|
Modules | lowerCamelCase | angularApp | |
Controllers | Functionality + 'Ctrl' | AdminCtrl | |
Directives | lowerCamelCase | userInfo | |
Filters | lowerCamelCase | userFilter | |
Services | UpperCamelCase | User | constructor |
Factories | lowerCamelCase | dataFactory | others |
Others
- Use:
$timeout
instead ofsetTimeout
$interval
instead ofsetInterval
$window
instead ofwindow
$document
instead ofdocument
$http
instead of$.ajax
$location
instead ofwindow.location
or$window.location
$cookies
instead ofdocument.cookie
This will make your testing easier and in some cases prevent unexpected behaviour (for example, if you missed $scope.$apply
in setTimeout
).
-
Automate your workflow using tools like:
-
Use promises (
$q
) instead of callbacks. It will make your code look more elegant and clean, and save you from callback hell. -
Use
$resource
instead of$http
when possible. The higher level of abstraction will save you from redundancy. -
Use an AngularJS pre-minifier (ng-annotate) for preventing problems after minification.
-
Don't use globals. Resolve all dependencies using Dependency Injection, this will prevent bugs and monkey patching when testing.
-
Avoid globals by using Grunt/Gulp to wrap your code in Immediately Invoked Function Expression (IIFE). You can use plugins like grunt-wrap or gulp-wrap for this purpose. Example (using Gulp)
gulp.src("./src/*.js") .pipe(wrap('(function(){\n"use strict";\n<%= contents %>\n})();')) .pipe(gulp.dest("./dist"));
-
Do not pollute your
$scope
. Only add functions and variables that are being used in the templates. -
Prefer the usage of controllers instead of
ngInit
. There are only a few appropriate uses of ngInit, such as for aliasing special properties of ngRepeat, and for injecting data via server side scripting. Besides these few cases, you should use controllers rather than ngInit to initialize values on a scope. The expression passed tongInit
should go through lexing, parsing and evaluation by the Angular interpreter implemented inside the$parse
service. This leads to:- Performance impact, because the interpreter is implemented in JavaScript
- The caching of the parsed expressions inside the
$parse
service doesn't make a lot of sense in most cases, sincengInit
expressions are often evaluated only once - Is error-prone, since you're writing strings inside your templates, there's no syntax highlighting and further support by your editor
- No run-time errors are thrown
-
Do not use
$
prefix for the names of variables, properties and methods. This prefix is reserved for AngularJS usage. -
Do not use
JQUERY
inside your app, If you must, useJQLite
instead withangular.element
. -
When resolving dependencies through the DI mechanism of AngularJS, sort the dependencies by their type - the built-in AngularJS dependencies should be first, followed by your custom ones:
module.factory('Service', function ($rootScope, $timeout, MyCustomDependency1, MyCustomDependency2) {
return {
//Something
};
});
Modules
-
Modules should be named with lowerCamelCase. For indicating that module
b
is submodule of modulea
you can nest them by using namespacing like:a.b
.There are two common ways for structuring the modules:
- By functionality
- By component type
Currently there's not a big difference, but the first way looks cleaner. Also, if lazy-loading modules is implemented (currently not in the AngularJS roadmap), it will improve the app's performance.
Controllers
-
Do not manipulate DOM in your controllers, this will make your controllers harder for testing and will violate the Separation of Concerns principle. Use directives instead.
-
The naming of the controller is done using the controller's functionality (for example shopping cart, homepage, admin panel) and the substring
Ctrl
in the end. -
Controllers are plain javascript constructors, so they will be named UpperCamelCase (
HomePageCtrl
,ShoppingCartCtrl
,AdminPanelCtrl
, etc.). -
The controllers should not be defined as globals (even though AngularJS allows this, it is a bad practice to pollute the global namespace).
-
Use the following syntax for defining controllers:
function MyCtrl(dependency1, dependency2, ..., dependencyn) { // ... } module.controller('MyCtrl', MyCtrl);
In order to prevent problems with minification, you can automatically generate the array definition syntax from the standard one using tools like ng-annotate (and grunt task grunt-ng-annotate).
Another alternative will be to use
$inject
like:angular .module('app') .controller('HomepageCtrl', HomepageCtrl); HomepageCtrl.$inject = ['$log', '$http', 'ngRoute']; function HomepageCtrl($log, $http, ngRoute) { // ... }
-
Avoid use of
$scope
service to define functions and properties as part of controllers. Use$scope
only if It's really needed: 0. For publish and subscribe to events:$scope.$emit
,$scope.$broadcast
, and$scope.$on
. 0. For watch values or collections:$scope.$watch
,$scope.$watchCollection
-
Prefer using
controller as
syntax and capturethis
using a variable:<div ng-controller="MainCtrl as main"> {{ main.things }} </div>
app.controller('MainCtrl', MainCtrl); MainCtrl.$inject = ['$http']; function MainCtrl ($http) { var vm = this; //a clearer visual connection on how is defined on the view vm.title = 'Some title'; vm.description = 'Some description'; $http.get('/api/main/things').then(function (response) { vm.things = response.data.things; // Adding 'things' as a property of the controller }); }
Avoid using
this
keyword repeatedly inside a controller:app.controller('MainCtrl', MainCtrl); MainCtrl.$inject = ['$http']; // Avoid function MainCtrl ($http) { this.title = 'Some title'; this.description = 'Some description'; $http.get('/api/main/things').then(function (response) { // Warning! 'this' is in a different context here. // The property will not be added as part of the controller context this.things = response.data.things; }); }
Using a consistent and short variable name is preferred, for example
vm
.The main benefits of using this syntax:
- Creates an 'isolated' component - binded properties are not part of
$scope
prototype chain. This is good practice since$scope
prototype inheritance has some major drawbacks (this is probably the reason it was removed on Angular 2):- It is hard to track where data is coming from.
- Scope's value changes can affect places you did not intend to affect.
- Harder to refactor.
- The 'dot rule'.
- Removes the use of
$scope
when no need for special operations (as mentioned above). This is a good preparation for AngularJS V2. - Syntax is closer to that of a 'vanilla' JavaScript constructor
Digging more into
controller as
: digging-into-angulars-controller-as-syntax - Creates an 'isolated' component - binded properties are not part of
-
If using array definition syntax, use the original names of the controller's dependencies. This will help you produce more readable code:
function MyCtrl(l, h) { // ... } module.controller('MyCtrl', ['$log', '$http', MyCtrl]);
which is less readable than:
function MyCtrl($log, $http) { // ... } module.controller('MyCtrl', ['$log', '$http', MyCtrl]);
This especially applies to a file that has so much code that you'd need to scroll through. This would possibly cause you to forget which variable is tied to which dependency.
-
Make the controllers as lean as possible. Abstract commonly used functions into a service.
-
Avoid writing business logic inside controllers. Delegate business logic to a
model
, using a service. For example://This is a common behaviour (bad example) of using business logic inside a controller. angular.module('Store', []) .controller('OrderCtrl', function () { var vm = this; vm.items = []; vm.addToOrder = function (item) { vm.items.push(item);//-->Business logic inside controller }; vm.removeFromOrder = function (item) { vm.items.splice(vm.items.indexOf(item), 1);//-->Business logic inside controller }; vm.totalPrice = function () { return vm.items.reduce(function (memo, item) { return memo + (item.qty * item.price);//-->Business logic inside controller }, 0); }; });
When delegating business logic into a 'model' service, controller will look like this (see 'use services as your Model' for service-model implementation):
// order is used as a 'model' angular.module('Store', []) .controller('OrderCtrl', function (order) { var vm = this; vm.items = order.items; vm.addToOrder = function (item) { order.addToOrder(item); }; vm.removeFromOrder = function (item) { order.removeFromOrder(item); }; vm.totalPrice = function () { return order.total(); }; });
Why business logic / app state inside controllers is bad?
- Controllers instantiated for each view and dies when the view unloads
- Controllers are not reusable - they are coupled with the view
- Controllers are not meant to be injected
-
Communicate within different controllers using method invocation (possible when a child wants to communicate with its parent) or
$emit
,$broadcast
and$on
methods. The emitted and broadcasted messages should be kept to a minimum. -
Make a list of all messages which are passed using
$emit
,$broadcast
and manage it carefully because of name collisions and possible bugs.Example:
// app.js /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Custom events: - 'authorization-message' - description of the message - { user, role, action } - data format - user - a string, which contains the username - role - an ID of the role the user has - action - specific action the user tries to perform * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
When you need to format data encapsulate the formatting logic into a filter and declare it as dependency:
function myFormat() { return function () { // ... }; } module.filter('myFormat', myFormat); function MyCtrl($scope, myFormatFilter) { // ... } module.controller('MyCtrl', MyCtrl);
-
In case of nested controllers use "nested scoping" (the
controllerAs
syntax):app.js
module.config(function ($routeProvider) { $routeProvider .when('/route', { templateUrl: 'partials/template.html', controller: 'HomeCtrl', controllerAs: 'home' }); });
HomeCtrl
function HomeCtrl() { var vm = this; vm.bindingValue = 42; }
template.html
<div ng-bind="home.bindingValue"></div>
Directives
- Name your directives with lowerCamelCase.
- 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. - Use custom prefixes for your directives to prevent name collisions with third-party libraries.
- Do not use
ng
orui
prefixes since they are reserved for AngularJS and AngularJS UI usage. - DOM manipulations must be done only through directives.
- 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. - Do not forget to use
$sce
when you should deal with untrusted content.
Filters
- Name your filters with lowerCamelCase.
- 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
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.
-
Use camelCase to name your services.
-
UpperCamelCase (PascalCase) for naming your services, used as constructor functions i.e.:
function MainCtrl(User) { var vm = this; vm.user = new User('foo', 42); } module.controller('MainCtrl', MainCtrl); function User(name, age) { this.name = name; this.age = age; } module.factory('User', function () { return User; });
-
lowerCamelCase for all other services.
-
-
Encapsulate all the business logic in services. Prefer using it as your
model
. For example:// order is the 'model' angular.module('Store') .factory('order', function () { var add = function (item) { this.items.push (item); }; var remove = function (item) { if (this.items.indexOf(item) > -1) { this.items.splice(this.items.indexOf(item), 1); } }; var total = function () { return this.items.reduce(function (memo, item) { return memo + (item.qty * item.price); }, 0); }; return { items: [], addToOrder: add, removeFromOrder: remove, totalPrice: total }; });
See 'Avoid writing business logic inside controllers' for an example of a controller consuming this service.
-
Services representing the domain preferably a
service
instead of afactory
. In this way we can take advantage of the "klassical" inheritance easier:function Human() { //body } Human.prototype.talk = function () { return "I'm talking"; }; function Developer() { //body } Developer.prototype = Object.create(Human.prototype); Developer.prototype.code = function () { return "I'm coding"; }; myModule.service('human', Human); myModule.service('developer', Developer);
-
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
config
callback like:angular.module('demo', []) .config(function ($provide) { $provide.provider('sample', function () { var foo = 42; return { setFoo: function (f) { foo = f; }, $get: function () { return { foo: foo }; } }; }); }); var demo = angular.module('demo'); demo.config(function (sampleProvider) { sampleProvider.setFoo(41); });
Templates
- Use
ng-bind
orng-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 useng-src
instead ofsrc
with{{ }}
template. - When you need to set the
href
of an anchor tag dynamically useng-href
instead ofhref
with{{ }}
template. - Instead of using scope variable as string and using it with
style
attribute with{{ }}
, use the directiveng-style
with object-like parameters and scope variables as values:
<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
- Use
resolve
to resolve dependencies before the view is shown. - Do not place explicit RESTful calls inside the
resolve
callback. Isolate all the requests inside appropriate services. This way you can enable caching and follow the separation of concerns principle.
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
- For newer versions of the framework (>=1.4.0) use the built-in i18n tools, when using older versions (<1.4.0) use
angular-translate
.
Performance
-
Optimize the digest cycle
- Watch only the most vital variables. When required to invoke the
$digest
loop explicitly (it should happen only in exceptional cases), invoke it only when required (for example: when using real-time communication, don't cause a$digest
loop in each received message). - For content that is initialized only once and then never changed, use single-time watchers like
bindonce
for older versions of AngularJS or one-time bindings in AngularJS >=1.3.0.
or<div> {{ ::main.things }} </div>
After that, no watchers will be created for<div ng-bind="::main.things"></div>
main.things
and any changes ofmain.things
will not update the view. - Make the computations in
$watch
as simple as possible. Making heavy and slow computations in a single$watch
will slow down the whole application (the$digest
loop is done in a single thread because of the single-threaded nature of JavaScript). - When watching collections, do not watch them deeply when not strongly required. Better use
$watchCollection
, which performs a shallow check for equality of the result of the watched expression and the previous value of the expression's evaluation. - Set third parameter in
$timeout
function to false to skip the$digest
loop when no watched variables are impacted by the invocation of the$timeout
callback function. - When dealing with big collections, which change rarely, use immutable data structures.
- Watch only the most vital variables. When required to invoke the
-
Consider decreasing number of network requests by bundling/caching html template files into your main javascript file, using grunt-html2js / gulp-html2js. See here and here for details. This is particularly useful when the project has a lot of small html templates that can be a part of the main (minified and gzipped) javascript file.
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
mgechev | morizotter | chatii2412 | pascalockert | yanivefraim | ericguirbal |
agnislav | ray7551 | mainyaa | LeonardCModoran | elfinxx | tiagobarreto |
Xuefeng-Zhu | SullyP | giacomocusinato | rubystream | lukaszklis | Spuffynism |
susieyy | cironunes | cavarzan | guiltry | MSafter | mingchen |
jmblog | luixaviles | andreasonny83 | kuzzmi | jabhishek | adambabik |
astalker | clbn | atodorov | apetro | valgreens | bitdeli-chef |
meetbryce | unseen1980 | cminhho | dwmkerr | kuzmeig1 | dominickolbe |
gsamokovarov | grvcoelho | yassirh | bargaorobalo | hermankan | jesselpalmer |
capaj | johnnyghost | jordanyee | whoan | nacyot | mariolamacchia |
mischkl | michaelmov | kirstein | mo-gr | mortonfox | cryptojuice |
nktssh | olafahn | olov | vorktanamobay | QuietHeartThinkingFar | raphaelfruneaux |
sahat | ganchiku | kaneshin | imaimiami | dooart | thomastuts |
UrielMiranda | vkarampinis | grapswiz | coderhaoxin | giantray | ntaoo |
seyyah | dchest |
Top Related Projects
Angular Style Guide: A starting point for Angular development teams to provide consistency through good practices.
AngularJS styleguide for teams
Deliver web apps with confidence 🚀
AngularJS - HTML enhanced for web apps!
JavaScript Style Guide
Clean Code concepts adapted for JavaScript
Convert
designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot