![]()
What is $destroy?
In AngularJS, the $destroy event is triggered when a scope is about to be removed (such as when navigating away from a page or removing a directive/component).
We use $destroy to clean up scope watchers, event listeners, and timers to improve performance and prevent memory leaks.
1️⃣ Why Use $destroy?
Prevents Memory Leaks – Stops unnecessary event listeners from running after the scope is gone.
Improves Performance – Reduces unnecessary $digest cycles.
Cleans Up Resources – Helps in cleaning up intervals, timeouts, and DOM events.
2️⃣ Cleaning Up $watch Listeners with $destroy
When we use $scope.$watch(), it adds a watcher to the digest cycle. If not cleaned up, it continues running even when the component is removed.
Without $destroy (Risk of Memory Leaks)
app.controller('MainCtrl', function($scope) {
$scope.counter = 0;
// Adding a watch
$scope.$watch('counter', function(newValue, oldValue) {
console.log('Counter changed:', newValue);
});
// When this scope is destroyed, the watcher still runs unless cleaned up
});
Problem: The $watch function stays active even after the controller is destroyed, leading to unnecessary updates.
With $destroy (Proper Cleanup)
app.controller('MainCtrl', function($scope) {
$scope.counter = 0;
// Storing the watcher in a variable
var unwatch = $scope.$watch('counter', function(newValue, oldValue) {
console.log('Counter changed:', newValue);
});
// Cleanup when the scope is destroyed
$scope.$on('$destroy', function() {
unwatch(); // Remove the watcher
console.log('Watcher removed');
});
});
Now, when the controller is destroyed, the $watch function is removed, avoiding unnecessary execution.
3️⃣ Cleaning Up $on Event Listeners with $destroy
If you’re listening for an event using $scope.$on(), it continues even if the scope is destroyed.
Without $destroy
app.controller('MainCtrl', function($scope) {
$scope.$on('myEvent', function(event, data) {
console.log('Event received:', data);
});
});
Problem: The event listener stays active even after the controller is removed, leading to performance issues.
Using $destroy to Remove the Event Listener
app.controller('MainCtrl', function($scope) {
var eventListener = $scope.$on('myEvent', function(event, data) {
console.log('Event received:', data);
});
// Cleanup event listener
$scope.$on('$destroy', function() {
eventListener(); // Remove event listener
console.log('Event listener removed');
});
});
Now, the event listener is removed when the scope is destroyed.
4️⃣ Cleaning Up $timeout and $interval
If you use $timeout or $interval, they keep running even after the component is removed, unless you stop them.
Without $destroy
app.controller('MainCtrl', function($scope, $interval) {
var timer = $interval(function() {
console.log('Interval running...');
}, 1000);
});
Problem: The interval keeps running even if the controller is destroyed.
Using $destroy to Cancel $interval
app.controller('MainCtrl', function($scope, $interval) {
var timer = $interval(function() {
console.log('Interval running...');
}, 1000);
// Cleanup interval on scope destroy
$scope.$on('$destroy', function() {
$interval.cancel(timer);
console.log('Interval cleared');
});
});
Now, the interval is stopped when the controller is destroyed.
5️⃣ $destroy in Directives
If your directive creates watchers or event listeners, you must clean them up when the directive is removed.
Example: Cleanup Inside a Directive
app.directive('customDirective', function() {
return {
restrict: 'E',
scope: {},
controller: function($scope) {
var unwatch = $scope.$watch('someValue', function(newValue) {
console.log('Value changed:', newValue);
});
// Cleanup on directive destroy
$scope.$on('$destroy', function() {
unwatch();
console.log('Directive watcher removed');
});
}
};
});
Now, the directive cleans itself up properly.
6️⃣ $destroy in AngularJS Components
For components, you can clean up watchers in the $onDestroy lifecycle hook.
app.component('myComponent', {
controller: function($scope, $interval) {
var timer = $interval(function() {
console.log('Interval running...');
}, 1000);
this.$onDestroy = function() {
$interval.cancel(timer);
console.log('Component destroyed, interval cleared');
};
}
});
Components use $onDestroy instead of $scope.$on('$destroy').
Summary
| What to Clean? | How to Clean Up? |
|---|---|
$scope.$watch() | Call unwatch() inside $destroy |
$scope.$on() | Call listener() inside $destroy |
$interval / $timeout | Use $interval.cancel() or $timeout.cancel() inside $destroy |
| DOM event listeners | Use element.off() inside $destroy |
| Components | Use $onDestroy() |
