Debugging an AngularJS application is crucial for identifying and resolving issues efficiently. Chrome DevTools provides powerful debugging features that can help developers inspect scopes, track performance, debug HTTP requests, and analyze dependency injections. This guide covers the most effective ways to debug AngularJS applications using Chrome DevTools.
1. Opening Chrome DevTools
To access Chrome DevTools:
- Windows/Linux: Press
F12
orCtrl + Shift + I
. - Mac: Press
Cmd + Option + I
. - Alternatively, right-click on the webpage and select Inspect.
2. Inspecting AngularJS Scopes
Since AngularJS relies on $scope, debugging scope values and tracking model changes is essential.
2.1 Accessing Scope in DevTools
- Open Chrome DevTools and navigate to the Elements tab.
- Select an AngularJS element (e.g.,
<div ng-controller="myController">
). - In the Console tab, type:
angular.element($0).scope()
$0
refers to the currently selected element.- The returned object contains all scope variables.
2.2 Modifying Scope Variables
To modify scope variables in real time:
angular.element($0).scope().message = "Updated Message";
angular.element($0).scope().$apply(); // Apply changes manually
2.3 Checking Isolated Scope of a Directive
If you’re debugging a custom directive:
angular.element($0).isolateScope()
- This returns the isolated scope attached to the directive.
3. Debugging Controllers
3.1 Listing All Controllers in the App
To check which controllers are active:
angular.module('myApp')._invokeQueue
This outputs all registered controllers.
3.2 Accessing a Specific Controller’s Scope
If your controller is bound to a DOM element:
angular.element(document.querySelector('[ng-controller="myController"]')).scope()
- This allows you to manually inspect or modify scope variables.
4. Debugging HTTP Requests
AngularJS applications rely on $http
or $resource
for API calls. Debugging these requests is crucial.
4.1 Checking Network Requests
- Open Chrome DevTools > Network tab.
- Filter by XHR to view API requests.
- Click on any request to inspect the Request URL, Headers, Response, and Status Code.
4.2 Capturing All API Calls in the Console
To log all outgoing API requests:
angular.module('myApp').config(function($httpProvider) {
$httpProvider.interceptors.push(function() {
return {
request: function(config) {
console.log("API Request:", config);
return config;
},
response: function(response) {
console.log("API Response:", response);
return response;
}
};
});
});
This logs every API request and response.
5. Debugging Dependency Injection Issues
If you encounter errors like:
Error: [$injector:unpr] Unknown provider: myServiceProvider <- myService
5.1 Listing All Services, Controllers, and Factories
angular.module('myApp')._invokeQueue.forEach(function(item) {
console.log(item[2][0]); // Logs service, controller, or factory names
});
5.2 Checking If a Service Exists
angular.module('myApp').hasOwnProperty('myService'); // Returns true or false
This ensures the service is correctly registered.
6. Monitoring AngularJS Digest Cycle
AngularJS uses $digest()
to update bindings. Too many watchers can impact performance.
6.1 Counting Active Watchers
To check how many watchers are running:
(function() {
var root = angular.element(document.getElementsByTagName('body'));
var watchers = [];
var f = function(element) {
angular.forEach(element.data().$scope ? element.data().$scope.$$watchers : [], function(watcher) {
watchers.push(watcher);
});
angular.forEach(element.children(), f);
};
f(root);
console.log('Total watchers:', watchers.length);
})();
- If the watcher count is too high, optimize performance by removing unnecessary bindings.
6.2 Identifying Slow Watchers
Use the Performance tab in Chrome DevTools:
- Click Record.
- Interact with the application.
- Analyze the timeline for long-running digest cycles.
7. Tracking Events with $broadcast
and $emit
AngularJS uses $broadcast()
and $emit()
for event propagation.
7.1 Debugging Emitted Events
var originalEmit = angular.element(document).injector().get('$rootScope').$emit;
angular.element(document).injector().get('$rootScope').$emit = function() {
console.log("Event emitted:", arguments);
return originalEmit.apply(this, arguments);
};
This logs all emitted events.
7.2 Debugging Broadcasted Events
var originalBroadcast = angular.element(document).injector().get('$rootScope').$broadcast;
angular.element(document).injector().get('$rootScope').$broadcast = function() {
console.log("Event broadcasted:", arguments);
return originalBroadcast.apply(this, arguments);
};
This helps track events flowing through $rootScope
.
8. Debugging Filters in AngularJS
Filters transform data inside AngularJS templates.
8.1 Listing All Filters
angular.module('myApp')._invokeQueue.forEach(function(item) {
if (item[1] === "filter") {
console.log("Filter:", item[2][0]);
}
});
8.2 Testing Filters in Console
var $filter = angular.element(document).injector().get('$filter');
console.log($filter('uppercase')('hello')); // Output: HELLO
- This lets you test filters without modifying templates.
9. Detecting Memory Leaks
Memory leaks in AngularJS can cause performance degradation.
9.1 Checking for Detached DOM Elements
- Open Chrome DevTools.
- Go to Memory > Heap Snapshot.
- Look for elements that should have been garbage collected but are still in memory.
9.2 Preventing Leaks
- Destroy event listeners when leaving a scope:
$scope.$on('$destroy', function() { element.off('click'); });
- Use one-time bindings (
::
) for static content:<p>{{ ::staticContent }}</p>