Angular JS best coding practice – Every coder should follow

Angular JS is one of the most widely used framework for SPA(Single Page Application) and for other dynamic web applications. There is a huge list of points which I think one should keep in mind while coding using Angular JS which could help you out in one way or another. Here is a list of some best practice tips that I follow and would like to recommend you all. I strongly believe a lot more features could be a part of this list and I invite you all to suggest and comment below in order to make this a complete best practice guide.

Jump to specific content-

  1. Dependency Injection
  2. $Scope
  3. Validations
  4. Memory – Task Management
  5. Events@ $rootScope
  6. Structuring Business Logic
  7. General Rules
Angular JS
Angular JS

1) Dependency Injection:

  1. Dependency injection is one of the best attribute of AngularJS framework and we should always use it. It will really help when we need to cover test cases of our application.
  2. Provide alias to dependency so that they will not rename during minification process, because in AngularJS dependencies are resolved by name.
angular.module(‘myApp’).controller('MyController', ['$scope',  'MyService',function($scope, MyService) {

	// controller logic

	}
   ]);

2) $Scope

  1. Treat scope as read only in templates i.e. even if AngularJS allows us to write code that modifies the scope in the templates, it is something that we must be very cautious about and probably shouldn’t do.
  2.  Treat scope as write only in controllers i.e. a controller is in charge of using another component, like a service, to get the data that the template will show and write this data in an object of the scope.
  • As a THUMB RULE, we must always have “.”  in the binding i.e. we should bind to an object in scope rather than a property directly, otherwise it can lead to unexpected behaviour in child $scope because $scope works on Java-script Prototypal inheritance.
    In below code we can see that superhero is an object on scope returned by Superhero service and same object used for binding in view.
<div class="form-group">
    <label class="control-label" for="name">Super Power</label>
       <div class="controls">
	  <input type="text" data-ng-model="superhero.superPower">
</div> 

 


$scope. superhero = Superheros.get({
	superheroId: $stateParams.superheroId
)};

  • The purpose of scope is to refer to model and not to be a model.
  • Model is our JavaScript object.

3) Validations

  1. Use attribute “novalidate” in form tag while using AngularJS validations to turn off HTML5 validations.
    <form name="reviewForm" ng-controller="ReviewController as reviewCtrl" ng-submit="reviewCtrl.addReview(product)" novalidate>
    
  2. We can use angular classes to change visibility and status of validations of controls.
    .ng-valid.ng-dirty{
        border-color: #FA787E;
    }
    .ng-invalid.ng-dirty{
        border-color: #FA787E;
    }
    

4) Memory – Task Management

  •  AngularJS broadcasts a $destroy event just before tearing down a scope and removing the scope from its parent. Listening for this event is crucial for cleaning up tasks and resources that otherwise might continue to chew up memory or CPU. Always register ‘destroy’ event to remove any memory leak prone code.

As an example, the following controller continuously updates a model value in one second intervals, and these updates will continue forever, even after the controller’s view is gone and the scope is removed from the parent. Even if the user will be navigating back and forth to a view that loads this controller, each navigation will add another timer that runs forever.

module.controller("MyController", function($scope, $timeout) {
    var onMyTimeout = function() {
        $scope.value += 1;
        $timeout(onMyTimeout, 100);
    };
    $timeout(onMyTimeout, 100);
    $scope.value = 0;

});

Listening for the $destroy event is an opportunity to halt the timer. One approach is to cancel the promise returned by $timeout.

module.controller("TestController", function($scope, $timeout) {var onTimeout = function() {
    $scope.value += 1;
    timer = $timeout(onTimeout, 100);
};

    var timer = $timeout(onTimeout, 100);
    $scope.value = 0;
    $scope.$on("$destroy", function() {

        if (timer) {
            $timeout.cancel(timer);
        }
    });
});

5) Events@ $rootScope

  1. We should only use scope events to communicate across the controllers in the current screen of our Single Page Application. If we need to only share data, then we should look at using Services instead.
  2. When firing events, unless we need every single scope in our whole application to be notified about an event, we don’t need to fire an event on $rootScope. If we only need it for the children scopes, $broadcast the event on our own scope. Parent scopes $emit it on our scope. This will also short circuit the event propagation, instead of going through the entire top-to-bottom flow.
  3. Services have no other alternative but to listen for events on $rootScope to get notifications. This is because services are initialized once across our application, and don’t get their own scope and this will be fine.
  4.  Generally we should not register event listeners on the $rootScope other than a service. This is a general cause of bugs in the AngularJS applications. This is because when we add an event listener on the $scope of a controller and the controller is destroyed (we navigate away from the page, or close a section), the listeners also get destroyed. When we add it to the $rootScope and navigate away from a controller, the listener remains and keeps alive and triggering. So we have to manually deregister it from $rootScope, or be safe and just not add it on $rootScope. But if we have to add an event to rootScope, do not forget to clean it in controller’s scope.

    <strong> </strong>
    
    var myEventHandler = $rootScope.$on('MyEvent', ‘My Data’);
          $scope.$on('$destroy', function() {
          myEventHandler();
    });
    
  5. If we know that there is only one listener, and you have already encountered it, we can stop further propagation of the event by calling event.stopPropagation() on the event object passed to the event listener function.

6) Structuring Business Logic

  1. Controllers should not reference DOM but just contain behavior, Directives should have DOM manipulation.
  2. Services should have logic independent of view.
  3. Don’t fight with HTML just expand it through Directives.
  4. It is better to have modular folder structure, so that we can create reusable/ distributable components.

7) General Rules

  1. Use ng-src in place of src for images.
  2. Use promise for handling call-backs. AngularJS has exposed “$q” service for it. A number of AngularJS services return promises: $http, $interval, $timeout.
  3. Do not minify angular.min.js because as per AngularJS team they has minified angular files with predefined settings, which may break if we minify again. So just concatenate it.
  4. Use $templateCache to cache html templates, if template caching is required.
  5. Always wrap 3rd party API call-backs in to $apply to notify AngularJS regarding out of environment changes.
  6. If we don’t want user to show our HTML until AngularJS has loaded, use ng-cloak directive.
    <div class="session ng-cloak">..............content............</div>
    .ng-cloak {
    /* this will change to block when scope and angular is ready */
    display:none;
    }
    
  7. Don’t use “ng” prefix for our directives to avoid any collisions. Create your custom one.Better to use <mycomponent> because <my:component> sometimes breaks on IE.
    <my-component>
    <my:component>
    
  8. Use $broadcast() , $emit() and $on() for events of  global relevance across the app (such as a user authenticating or the app closing). If we need events specific to modules, services or widgets we should opt for Services, Directive Controllers etc.
  9. Don’t use self-closing tag because some browsers don’t like them. Use “<product-title></product-title >” rather than “<product-title/>”.

Do comment and share your views and suggestions with us.

Keep Learning. Happy Learning 🙂

Recommended -

Subscribe
Notify of
guest
14 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
jon
jon
9 years ago

I find it’s easier to take care of dependency injection aliases in your build process with ngAnnotate and gulp.

rahul garg
rahul garg
9 years ago
Reply to  jon

Surely, if we are using gulp or grunt in our build process we should go for ngAnnotate. Thanks for pointing out.

Mike
Mike
9 years ago
Reply to  jon

Explicit injection is required if you want your module to be used in a project that does not use grunt or gulp

jon
jon
9 years ago
Reply to  Mike

If you are distributing your project to to be used in another project, you can still use gulp or grunt to build it, then include it in your other projects.

Blair Morris
Blair Morris
9 years ago

7.1 Use ng-src instead of src

Would you say this is a hard rule, or only when your source url is a computed value? I typically use it only when I’m using a value (or multiple values pieced together) from my scope.

rahul garg
rahul garg
9 years ago
Reply to  Blair Morris

This is must have if we are using computed value and good to have for static path if you do want show partial content to user. If we use sec only , I believe we should entertain point 7.6. so hide partial rendering of our page.
The angularjs directive ng-src is used to prevent the browser from loading the resource (e.g. image) before the handlebars get parsed.

Mickey Vashchinsky
Mickey Vashchinsky
9 years ago

Hi.

Thank you for your article.

I have some points though:

1. The second way to preserve the parameters is using:

var MyController = function($scope, greeter) {
//...
}
MyController.$inject = ['$scope', 'MyService']

Among other solutions there are for build time. One is using ng-annotate plugins for Grunt and Gulp

2. There is a newer ‘best practice’ to use ‘controller as’ feature of Angular 1.2+ (I think) and not use $scope for view model.

7.6 There is a typo in the description: ‘ng-clock’ instead of ‘ng-cloak’.

Thank you

rahul garg
rahul garg
9 years ago

You are correct. “Controller As” is very useful feature specially in case of nesting controllers and it also provide feasibility to work with out loved keyword “this” .

Dan Cancro
9 years ago

One little typo… ‘rename during magnification process’ should be ‘rename during minification process’

rahul garg
rahul garg
9 years ago
Reply to  Dan Cancro

Nice catch. Thanks !!

Mike
Mike
9 years ago

Under Structuring business logic you write
“Controllers should not reference DOM but just contain behavior, Directives should have DOM manipulation.”
Do you mean directives (controllers/link functions of directives) should NOT have DOM manipulation?

rahul garg
rahul garg
9 years ago
Reply to  Mike

No, I mean controller should not have any DOM manipulation, but just contain viewmodel for behaviour. Directives should be take care of DOM manipulations.

Mobile Tester
Mobile Tester
9 years ago

Any best practices concerning node and angular?

Malay Ladu
7 years ago

Hello Rahul,

Interesting points…

Curious to know whether we can do Object Oriented Programming in Angular JS like we do in PHP?

If yes, what is the best practice? Have you came across any application which follow this structure?

Any help would greatly be appreciated.

14
0
Would love your thoughts, please comment.x
()
x
Index