Debugging AngularJS

When we’re building large Angular apps, it’s not uncommon to run into head-scratching issues that are seemingly difficult to uncover and resolve.

Debugging from the DOM

Although not always necessary nor a first step, we can get access to the Angular properties that are attached to any DOM element. We can use these properties to peek into how the data is flowing in our application.

We should never rely on fetching element properties from a DOM element during the lifecycle of an application. The techniques are presented as techniques for debugging purposes.

To fetch these properties from the DOM, we need to find the DOM element in which we’re interested. If we have the full jQuery library available, we can use the jQuery selector syntax: $("selector").

We don’t need to rely on jQuery, however, to target and fetch elements from the DOM. Instead, we can use the document.querySelector() method.

Note that the document.querySelector() is not available on all browsers and is generally good for non-complex element selections, whereas Sizzle (the library jQuery uses) or jQuery support more complex selections.

We can retrieve the $rootScope from the DOM by selecting the element where the ngApp directive is placed and wrapping it in an Angular element (using the angular.element() method).

With an Angular element, we can call various methods to inspect our Angular app from inside the DOM. To do so, we need to select the element from the DOM. Using only JavaScript and Angular, we can do so in this way:

var rootEle = document.querySelector("html");
var ele = angular.element(rootEle);

With this element, we can fetch various parts of our application.

scope()

We can fetch the $scope from the element (or its parent) by using the scope() method on the element:

var scope = ele.scope();

Using the element’s scope, we can inspect any scope properties, such as custom variables that we set on the scope in our controllers. We can peek into the elements looking into its $id, its $parent object, the $watchers that are set on it and even manually walk up the scope chain.

controller()

We can fetch the current element’s controller (or its parent) by using the controller() method:

var ctrl = ele.controller();
// or
var ctrl = ele.controller('ngModel');

injector()

We can fetch the injector of the current element (or the containing element) by using the injector() method on the selected element.

var injector = ele.injector();

With this injector, we can then then instantiate any Angular object inside of our app, such as services, other controllers, or any other object.

inheritedData()

We can fetch the data associated with an element’s $scope simply by using the inheritedData() method on the element:

ele.inheritedData();

This inheritedData() method is how Angular finds data up the scope chain as it walks up the DOM until it’s found a particular value or until the top-most parent has been reached.

If you’re using Chrome, we can use a shortcut with the developer tools. Simply find the element you’re interested in, right click on it in the browser, and select inspect element. The element itself is stored as the $0 variable, and we can fetch the Angular-ized element by calling: angular.element($0).

Debugger

Google’s Chrome has its own debugger tool to create a breakpoint in our code. The debugger statement will cause the browser to freeze during execution, allowing us to examine the running code from inside the actual application and at the point of execution inside the browser.

To use the debugger, we can simply add it inside the context of our application code:

angular.module('myApp', [])
.factory('SessionService', function($q, $http) {
  var service = {
    user_id: null,
    getCurrentUser: function() {
      debugger; // Set the debugger inside 
                // this function
      return service.user_id;
    }
  }
    return service;
});

Inside this service, we’ll call the debugger; method that effectively freezes our application.

As long as the Chrome development tools are open in our browser, we can use console.log() and other JavaScript commands at the point where this application code executes.

When we’re done debugging the application code, we need to make sure we remove this line, because it will freeze the browser, even in production.

Angular Batarang

Angular Batarang is a Chrome extension developed by the Angular team at Google that integrates very nicely as a debugging tool for Angular apps.

Batarang chrome extension

Installing Batarang

To install Batarang, we simply need to download the application from the web store or from the GitHub repo: https://github.com/angular/angularjs-batarang.

Once our installation is set, we can start up the extension by navigating to our developer tools and clicking enable to enable Batarang to start collecting debugging information about our page.

Batarang allows us to look at scopes, performance, dependencies, and other key metrics in Angular apps.

Inspecting the Models

After we’ve started up Batarang, the page will reload, and we’ll notice that we have a panel that enables us to select different scopes in our page.

We can select a scope by clicking on the + button, finding the element we’re interested in and clicking on it.

Once we select a scope using the inspector, we can look at all the different properties on our scope element and their current values.

Model inspector

Inspecting Performance

We can also peek into the performance of our application by using the performance section of Batarang.

In this panel, we get a peek into the watch list of the application at the different scopes as well as the amount of time that each expression takes, both in absolute time and percentage of the overall application time.

Performance inspector

Inspecting the Dependency Graph

One very nice feature of the Batarang tool is its ability to visualize the dependency graph inline. We can look at the dependencies of our application and view the different libraries of our application to see what they depend upon and track libraries that aren’t dependencies of the application at all.

Dependency graph

Visualizing the App

Batarang allows us to look deep into the application on the page itself. Using the Options panel, we can look at:

Applications

The different applications that are on a single page (the ngApp directive uses).

Bindings

The bindings that are set in the view, where we use either ng-bind or elements that are surrounded in the template tags {{ }}.

Scopes

The scopes in the view that we can target and inspect more deeply

The options panel also allows us view the Angular version of the app and what we’re using or not using from a CDN.

Options

All in all, the Batarang tools gives us a lot of power when diving into how our Angular apps work in real time.

 
This page is a preview of ng-book.
Get the rest of this chapter plus 600 pages of the best Angular content on the web.

 

Ready to master AngularJS?

  • What if you could master the entire framework – with solid foundations – in less time without beating your head against a wall? Imagine how quickly you could work if you knew the best practices and the best tools?
  • Stop wasting your time searching and have everything you need to be productive in one, well-organized place, with complete examples to get your project up without needing to resort to endless hours of research.
  • You will learn what you need to know to work professionally with ng-book: The Complete Book on AngularJS or get your money back.
Get it now