The first version of AngularJS was released in 2009 and is becoming more popular for developing web applications. The latest (January 2015) Tech Radar by ThoughtWorks (http://www.thoughtworks.com/radar) places AngularJS in the “trial” sections which means that they find it “worth pursuing”. In Kainos we use it in various projects and I would like to share some tricks and tips. Some of them are very basic but still might be helpful for everyone.

1. Angular and Chrome Developer Tools.
During the development process it’s often necessary to check the status of the scope. Of course we can put a breakpoint in our javascript or just add a temporary text field to the page, but those solutions require us to perform an action on the page which may cause changing the state, or modifying the source code and refreshing the page which can be time consuming or even impossible (ie. it’s already on production).
I think that the best solution is to use Chrome Developer Console to browse the scope. All we have to do is to inspect a specific part of the page (different sections may have different scopes). Lets use the official AngularJS tutorial page to test this out: http://angular.github.io/angular-phonecat/step-7/app/#/phones

Screen-Shot-2015-01-09-at-15.40.30

and then switch to the Console tab and type “angular.element($0).scope()” ($0 stands for selected element, instead we could use any other function that returns a DOM node like “document.getElementById()”):

Screen-Shot-2015-01-09-at-15.42.39

as we can see console has displayed the scope properties with “query” field.

2. Passing data between scopes.
One of biggest problems when beginning to work with angular is understanding how ng-model works. The problem is that it’s valid just in specific scope and a new scope can be created by “ng-repeat” or “ng-if” procedure. The problem is presented in this example code:

   <div ng-app>
      <input type="text" ng-model="data">
      <div ng-repeat="i in [1]">
         <input type="text" ng-model="data"><br/>
         inner scope:{{data}}
      </div>
      outer scope:{{data}}
   </div>

http://jsfiddle.net/hv34kejf/

If the first input is edited, the text is propagated, inner scope inherites from outer one and propagates the data. If the second field is edited this connection is broken because inner scope creates its own field so it no longer inherits from the outer one. It is wider explained in this article: https://github.com/angular/angular.js/wiki/Understanding-Scopes.
To prevent such problems we can use services to share data between scopes but I think it’s form over content, especially when we’re using only one controller. It’s much easer to keep everything in objects:

<div ng-app>
   <input type="text" ng-model="data.text">
   <div ng-repeat="i in [1]">
      <input type="text" ng-model="data.text"><br/>
      inner scope:{{data.text}}
   </div>
   outer scope:{{data.text}}
</div>

http://jsfiddle.net/od1s7npo/

Now everything works fine, because the inner scope is no longer creating a new field in scope, it’s just updating outer scopes property “data”. Another solution might be using:

3. „Controller As” approach
Instead of using scope as a container for all data and functions, we can use a controller as itself. Example:

One should notice that in controller we no longer use the “$scope” variable, but we assign everything to a controller object ‚this.text = “”’. In HTML templates we should just define a name for our controller variable: ‚ng-controller=”MainCtrl as ctrl”’ and everything works like a charm. There are many people in favour of this approach and many who are opposed, but I think it might be useful for inexperienced developers who are having problems with understanding the scope approach.

4. Filtered array outside ng-repeat.
In the official AngularJS tutorial, one can discover how easy it is to filter an array and how useful might it be (https://docs.angularjs.org/tutorial/step_03). But sometimes there is a need of saving the actual result and using it outside of the scope:


<div ng-app ng-controller="MainCtrl">
   <input type="text" ng-model="text">
   <div ng-repeat="i in arr | filter: text">
      {{i}}
      <br/>
   </div>
   count outside scope: {{arr.length}}
</div>

http://jsfiddle.net/sjw3xx0j/

the text under the list is always: „count outside scope: 4” because “arr” variable always contains full array. To save the results, all we have to do is to create a new variable in the HTML template in ng-repeat directive: ng-repeat=”i in result = (arr | filter: text)”

<div ng-app ng-controller="MainCtrl">
   <input type="text" ng-model="text">
   <div ng-repeat="i in result = (arr | filter: text)">
      {{i}}
      <br/>
   </div>
   count outside scope: {{result.length}}
</div>

http://jsfiddle.net/Lqaagv3w/

5. Controller inheritance.
Sometimes, when having many similar controllers, there might be a need to re-use some of functionaly. We might use a inheritance of controllers by nesting HTML nodes with ng-controller directive like in this example:

HTML:

<div ng-app ng-controller="ParentCtrl">
   <div ng-controller="ChildCtrl">
   {{parentText}}
   <br/>
   {{childText}}
   <br/>
   {{text}}
   </div>
</div>

JS:

function ChildCtrl($scope) {
   $scope.childText = "childText"
   $scope.text = "childText"
}

function ParentCtrl($scope) {
   $scope.parentText = "parentText"
   $scope.text = "parentText"
}

http://jsfiddle.net/12dn6gvh/

but this can cause mess in the HTML template, instead we can implement inheritance directly in the controller implementation:

HTML:

<div ng-app ng-controller="ChildCtrl">
   {{parentText}}
   <br/>
   {{childText}}
   <br/>
   {{text}}
</div>

JS:

function ChildCtrl($scope, $controller) {
   $controller("ParentCtrl", {$scope: $scope});
   $scope.childText = "childText"
   $scope.text = "childText"
}

function ParentCtrl($scope) {
   $scope.parentText = "parentText"
   $scope.text = "parentText"
}

http://jsfiddle.net/L32h9kwx/

this makes the template clearer, and encapsulates the whole implementation of the controller in JavaScript code, so we can be sure that it won’t be used in a wrong way by other developers in our team.
Of course one have to remember that inheritance is not always a solution for all problems, so consider using different approaches like composition and choose wisely ;-)