Debugging AngularJS applications can be challenging due to its two-way data binding, digest cycle, and dynamic nature. By using proper debugging techniques, you can efficiently identify and resolve issues in your application.
1. Understanding Common AngularJS Issues
Before jumping into debugging techniques, it’s important to recognize common problems:
Scope-related issues – Data not updating as expected due to $scope
mismanagement
Digest cycle errors – Infinite $digest
loop or failure to update the UI
Incorrect dependency injection – Errors due to minification or missing dependencies
API request failures – $http
calls returning errors or unexpected data
Performance bottlenecks – Too many $watchers
or frequent $digest
cycles
Memory leaks – Unremoved watchers, event listeners, or persistent services
2. Using Chrome DevTools for Debugging
Chrome DevTools provides powerful features to inspect and debug AngularJS applications.
Inspecting Scope Variables
To inspect AngularJS $scope
in DevTools:
1️⃣ Open Chrome DevTools (F12
or Ctrl+Shift+I
).
2️⃣ Select the Elements tab and click on an AngularJS-bound element.
3️⃣ Run the following command in the Console to inspect the $scope
:
angular.element($0).scope();
This helps you verify if the correct values are being assigned.
Debugging Controllers and Services
You can manually inspect AngularJS controllers and services using DevTools:
angular.element(document.body).injector().get('MyService');
This retrieves the MyService instance, allowing you to manually test methods.
Checking Active Watchers
Too many watchers can slow down your application. Use the following command to check the total watchers:
(function() {
var total = 0;
var elements = document.querySelectorAll('*');
angular.forEach(elements, function(element) {
var scope = angular.element(element).scope();
total += (scope && scope.$$watchers) ? scope.$$watchers.length : 0;
});
console.log('Total watchers:', total);
})();
If this number keeps increasing, you might have a memory leak due to unnecessary watchers.
3. Using $log
Instead of console.log()
Instead of console.log()
, AngularJS provides $log
service, which:
✔ Works across browsers and supports dependency injection
✔ Can be disabled in production mode
✔ Provides better debugging features
Example Usage
app.controller('MyController', function($scope, $log) {
$scope.data = "Hello AngularJS";
$log.info("Info: ", $scope.data);
$log.warn("Warning message");
$log.error("Error message");
});
Replace console.log()
with $log
for better debugging.
4. Using $exceptionHandler
to Catch Global Errors
AngularJS provides the $exceptionHandler
service to catch uncaught exceptions.
Custom Global Error Logging
app.factory('$exceptionHandler', function($log) {
return function(exception, cause) {
$log.error('AngularJS Error:', exception, 'Cause:', cause);
};
});
Helps log uncaught exceptions globally.
5. Handling API Errors with $httpInterceptor
Intercept API requests to handle failures gracefully.
Using an HTTP Interceptor for Error Handling
app.factory('httpInterceptor', function($q, $log) {
return {
responseError: function(rejection) {
$log.error('HTTP request failed:', rejection);
return $q.reject(rejection);
}
};
});
app.config(function($httpProvider) {
$httpProvider.interceptors.push('httpInterceptor');
});
This captures all failed API requests in one place.
6. Debugging $digest
Cycle Issues
When you see the error:
“Error: $digest already in progress”
“Too many $digest iterations”
It means that AngularJS is repeatedly evaluating watchers.
Solution: Use $applyAsync()
Instead of $apply()
Instead of:
$scope.$apply(function() {
$scope.data = "Updated!";
});
Use:
$scope.$applyAsync(function() {
$scope.data = "Updated!";
});
$applyAsync()
schedules a digest for the next tick, preventing infinite loops.
7. Debugging Performance Issues
Using the Timeline in Chrome DevTools
1️⃣ Open Chrome DevTools (F12
).
2️⃣ Go to the Performance tab.
3️⃣ Click Start Recording, then interact with your app.
4️⃣ Stop the recording and look for long-running scripts or high repaint times.
Helps identify slow components.
Avoiding Unnecessary Watchers
Too many watchers slow down your app.
Bad Practice
<p>{{ message }}</p> <!-- This creates a watcher -->
Better Approach: Use One-time Binding (::
)
<p>{{ ::message }}</p>
Reduces digest cycle load.
8. Using ng-strict-di
for Dependency Injection Debugging
Error: $injector:modulerr
due to incorrect dependency injection
Solution: Use Strict Dependency Injection (ng-strict-di
)
Add ng-strict-di
to your <html>
tag:
<html ng-app="myApp" ng-strict-di>
Catches dependency injection errors before runtime.
9. Resetting Application State for Testing
During debugging, you may need to reset the application state.
Using $rootScope.$broadcast
to Reset Components
$rootScope.$broadcast('resetApp');
And in your controllers:
$scope.$on('resetApp', function() {
$scope.data = null;
});
Resets all app components easily.
10. Debugging AngularJS with Batarang (Chrome Extension)
🔹 Install AngularJS Batarang from Chrome Web Store
🔹 Helps visualize scope hierarchy, watchers, and bindings
🔹 Useful for inspecting scope variables and performance bottlenecks