JumpStart Angular : Best Practices

In previous posts we have seen various aspects of AngularJS. We have seen model binding with ng-model, various angular directives like ng-appng-controllerng-clickng-repeat etc. Using these we can build highly interactive and dynamic website.

So, it is the right time to get to know some of the best practices. Following these practices will improve code quality and helps us to overcome some hiccups. We will look into various examples explaining these and will try to follow these practices in further blog posts.

1. ng-app with application name.

We have used ng-app in all our examples. ng-app defines the code block that is controlled by AngularJS. In most of the real time scenarios, we may need to write our own filters, define routing for our application or define new directive for our application. So we need to customize angular for our needs and ng-app is the place for that. Till now we have used parameterless ng-app directive,  which bootstraps the default angular behavior on our application. We will look into ng-app with parameter,  called application module  A single page can have only one ng-app directive. (If we bootstrap manually, it is possible to have multiple ng-app, but it is not advised).


With ng-app we can inject external modules( like angular-ui) or any custom modules. In this example i have declared an external module app.Module1

. The value method defines a service with in module scope. In app.Module1, i have defined sayHello object with welcome function. TestApp is another module which is used as my application module. You can find ng-app='TestApp' in HTML code. app.Module1 is added as an dependency to TestApp module. sayHello service is injected to testController. If we will replace ng-app='TestApp' with ng-app, the service will not be loaded.

2. ng-controller in application scope.

Controllers are javascript functions. By default javascript function parameters are position based, i.e. first parameter will always bind to first argument, so during minification parameter names are shortened and its references are updated  But in case of angular parameters are services that are injected to controller. It depends on parameter name, so if we minify our controller javascript dependencies will not be resolved  To overcome this angular provides one more way we can define controller. We can define a controller as an object array where first arguments are the string equivalent of service names and last argument is the controller function. During minification strings are not minified as they are values not references. Angular will always bind first string to first parameter and so on.In this example angular bind s with $scope and f with $filter respectively. In real world scenarios a controller always belongs to an application. So it is always advisable to define controller in application scope. In above example myController can be used with any ng-app modules. To define a controller in application scope, we can use controller() method of module.

Above example is same as previous, but i have defined the controller with in myApp module. So myController can only be used with in myApp module. If we remove the myApp module from HTML, we will not get expected result.

3. ng-bind/ng-cloak instead on inline expression ({{..}})

We have used {{..}} (angular expression) in many of my examples. It seems quite easy to bind an expression with in {{}} braces. But it has got one annoying disadvantage. Until angular is loaded and bootstrapped your HTML, you will see the angular expression, but it will go away once angular is loaded. In below image, i have put an break point to show above effect called Flash Of Unstyled Content (FOUC)
Angular provides two solutions to above problem i.e. ng-bind and ng-cloak . ng-bind='expression' is used as an attribute and it tells compiler to replace the innerHTML with result of the expression. In following example, the expression name||'Guest' tells angular to display Guest until name is defined and the innerHTML Guest, will be shown when angular is not bootstrapped.
ng-cloak is similar to ng-bind, but it hides the innerHTML till application is bootstrapped. In angular.js following css rule is applied which will hide the ng-cloak DOM element.
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
  display: none !important;

But, these effect will be applied 

only after angular.js is loaded.

 So we can add above css rule to site.css for better effect. Moreover attribute based styling in not supported in IE8 and earlier. To be in safer side we can add

ng-cloak with class='ng-cloak'.

4. Don't do DOM manipulation, use angular directives effectively.

Angular provides a rich framework which supports two-way-binding of the model and  views. With effective use of various angular directives we can eliminate the DOM manipulations. We can use ng-model,ng-view,ng-show,ng-click etc to access required behaviors. We will see a DOM manipulation examples using jQuery and Angular.
In above example we have done few simple DOM manipulation. As you can see javascript code is filled with HTML selectors. Now we will try to do same with angular.
As you see, my javascript code is much more neat and simple. Angular framework takes care of these DOM manipulation. This is a simple example, when we will learn about much more angular directives, we can avoid a lot of code. (like ajax request and update DOM etc)

5. $scope is not the model but a reference to model.

We have used $scope many times, declared variables in $scope and used in views. But $scope is not meant for this. Ideally we need to define models with required properties and refer model in $scope. As per best practice, ng-model should have '.' in its name  This is done to avoid prototypical inheritance problem. In angular we will face similar problem, if a property is defined in $scope and it is updated in child scope. Lets spend some time understanding this,

Consider above two scenarios, assume Parent is $scope object. Until we have overridden the myVar in child scope, any change to Parent.myVar will be reflected when we will call Child.myVar (as it accesses same object). If we will override myVar in child scope then Parent.myVar and Child.myVar will point to two different values.

In above example if we change value in Parent scope, it will be reflected in Child scope. But if we change value in child scope, it will create a new variable in child scope. After this, if we will modify Parent , the changes will not be reflected in Child scope. Lets wrap fName in a model person. Now when we will modify person.fName, it will refer to person in parent scope, so it will behave as expected.

We should always create a model which contains required variables and refer the model in $scope. So, 

$scope should be read-only in view. Write to a model in $scope , not in scope directly.

Posted by