The best applications are coded properly. This sounds like an obvious statement, but by ‘properly’, I mean that the code not only does its job well, but is also easy to add to, maintain and debug.
The main reason for using a consistent set of coding conventions is to standardise the structure and coding style of an application so that you and others can easily read and understand the code.
Good coding conventions result in precise, readable, and unambiguous source code that is consistent with other language conventions and as intuitive as possible.
Coding style is made up of numerous small decisions based on the language:
- How and when to use comments
- Tabs or spaces for indentation (and how many spaces)
- Appropriate use of white space
- Proper naming of variables and functions
- Code grouping an organisation
- Patterns to be used
- Patterns to be avoided
Here we are giving some basic coding standards for AngularJS that should be followed for better coding.
Coding Rules
1. Single Repository :
Defining a single component per file helps with code maintenance. Rather than defining a module (and its dependencies), a controller, and a factory all in the same file, separate each one into their own files.
2. 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 functionality and lower-level divisions by component types.
The application is organised by the self-contained features that it required. Each feature can be plugged into or out of the application with relative ease. Both development and testing is conducted within the scope of each feature.
. ├── app │ ├── src │ │ ├── app.module.js │ │ ├── app.config.js │ │ ├── app.route.js │ │ ├── home │ │ │ ├── home.module.js │ │ │ ├── home.route.js │ │ │ ├── list │ │ │ │ ├── homeList.controller.js │ │ │ │ ├── homeList.service.js │ │ │ │ ├── homeList.directive.js │ │ │ ├── details │ │ │ │ ├── homeDetails.controller.js │ │ │ │ ├── homeDetails.service.js │ │ │ │ ├── homeDetails.directive.js │ │ │── about │ │ │ ├── about.module.js │ │ │ ├── about.controller.js │ │ │ ├── about.route.js │ │ │ ├── about.service.js │ │ ├── shared │ │ │ ├── shared.module.js │ │ │ ├── shared.controller.js │ │ │ ├── shared.directive.js │ │ │ ├── shared.filter.js │ │ │ └── shared.service.js ├── templates │ │── home │ │ │ ├── homeList.tpl.html │ │ │ ├── homeDetails.tpl.html │ │── about │ │ │ ├── about.tpl.html │ │── shared │ │ │ ├── shared1.tpl.html │ │ │ ├── shared2.tpl.html ├── bower_components └── e2e-tests
3. Naming Conventions :
Main Standards | Example |
---|---|
Module – lowerCamelCase | myApp |
Controllers – Functionality(upperCamelCase) + ‘Controller’ | LoginController |
Directives – lowerCamelCase | validatePhone |
Services – UpperCamelCase | LoginService |
Factories – UpperCamelCase | LoginFactory |
4. Modules :
Modules should be declared using the global angular variables
// main module (function (){ "use strict"; angular.module('app’, ['app.user’]); })(); // child module (function (){ "use strict"; angular.module('app.user’, []); })();
» No additional global variables are required
» You can access your modules from everywhere
» Modules can be placed into different files
» You can use the function-form of use strict;
5. Controllers :
Do not manipulate DOM in your controllers, this will make your controller’s harder for testing and will violate the Separation of Concerns principle.
The naming of the controller is done using the controller’s functionality (for example shopping cart, homepage, admin panel) and the substring Controller in the end. (LoginController, AdminController etc). The controllers should not be defined as globals.
(function () { "use strict"; angular.module('app.user') .controller('UserListController', UserListController); UserListController.$inject = ['$scope', '$state', ‘userService’]; function UserListController($scope, $state, userService) { // body } })();
Make the controllers as clean as possible. Abstract commonly used functions into a service.
6. Directives :
Directives are a way to attach a specified behaviour to a DOM element or even to transform an element and its children.
- Attributes
- Elements
Attributes
When you are decorating an existing element with new functionality, directives should be applied as attributes.
<span animate="shape">Show animation</span>
These directives should be developed in a generic way, with minimal understanding of the element content and can be used across an application.
Elements
When creating self-contained components, you should use the element notation. This allows us to describe functionality in templates by applying directives as a domain specific language.
<phone-number></phone-number>
Each element is responsible for delivering its described functionality. The parent template is more descriptive and easier to maintain as you can simply switch functionality on or off by adding or removing the element.
Element directives should be placed alongside their corresponding feature.
7. Services :
Services are responsible for the business logic in your application.
All AngularJS services are singletons, which means that there is only one instance of a given service per injector.
There are two ways to create service :
- Factory
- Service
Using Factory method
(function (){ "use strict"; angular.module('mainApp') .factory('userService', userService); userService.$inject = ['$resource']; function userService($resource) { return $resource( '/api/user/:userId', { userId: '@userId' }, { update: { method: 'PUT' } }); }; })();
When declaring factoryName as an injectable argument you will be provided the value that is returned by invoking the function reference passed to module.factory.
Using Service Method
(function (){ "use strict"; angular.module('mainApp') .service('userService',userService); userService.$inject = ['$resource']; function userService($resource) { return $resource( '/api/user/:userId', { userId: '@userId' }, { update: { method: 'PUT' } }); }; })();
When declaring serviceName as an injectable argument you will be provided with the instance of a function passed to module.service.
8. Dependency Injection :
There are two types of dependencies you can include in your modules and controllers. The first is listing your required modules and the second is injecting services into your controllers.
- Inline Array Annotation
- $inject Property Annotation
Inline Array Annotation
userModule.controller('MyController', ['$scope', 'constant', function($scope, constant) { // … }]);
This is a fairly standard process of how we require modules in AngularJS.
$inject Property Annotation
Should be done explicitly to prevent errors during minification and disjointed dependencies within your code. This is the most recommended way to inject dependency.
(function () { "use strict"; angular.module('app.user') .controller('UserListController', UserListController); UserListController.$inject = ['$scope', 'constant']; function PatientListController($scope, constant) { // body } });
Written by Dipali Shinde, Sr. Software Engg. at zCon Solutions