AngularJS: $onDestroy component hook makes $scope unnecessary in hybrid Cordova mobile application events unbinding and in interval/timeout cleaning

Radek Anuszewski
2 min readMay 8, 2016

Unwanted marriage with $scope before an era of components

When we write hybrid mobile application with AngularJS and Cordova and want to make some additional actions for clicking back button, like clearing intervals, we have something like this

document.addEventListener(
'backbutton',
function () {
vm.clearIntervals();
vm.goToPreviousPath();
}
);

And in the dark ages before an era of AngularJS components, when we need to clear it when controllers is destroyed (because user clicks on navigation link and listening on back button in new context has so sense or back button should have different actions in new context), we had to inject $scope and listen to $destroy event:

$scope.$on($destroy, function () {
vm.clearIntervals(); //we always has to do it
document.removeEventListener(
'backbutton',
function () {
vm.clearIntervals();
vm.goToPreviousPath();
}
);
});

And, of course, it applies not only to hybrid applications, but for any application which uses intervals or has to do any job before controller is destroyed. So, we knew that we should get rid of using $scope in favor to controllerAs syntax (widely described here: Todd Motto: Digging into Angular’s “Controller as” syntax) because of $scope does not exist in Angular 2 in the same way as in 1 and $scope exposes many private Angular things — and we used to use it, which makes code unreadable and hard to maintain. On of the examples of it is $$phase, which is described by Scott Moss in his “ngDarwinAward” talk. And for me, $destroy event was the only one reason to still inject $scope to my controllers.

$onDestroy component hook as our savior

In my previous post: AngularJS: $onInit component hook and simplifying controller tests I put my pennyworth in use cases of $onInit hook, which runs when controller is instantiated. In this post other hook, $onDestroy, which runs when controllers is destroyed can really help with issues described above.

With new $onDestroy hook, introduced in 1.5.3 instead of using $scope I can place cleaning logic inside $onDestroy function:

vm.$onDestroy = function () {
vm.clearIntervals(); //we always has to do it
document.removeEventListener(
'backbutton',
function () {
vm.clearIntervals();
vm.goToPreviousPath();
}
);
});

And my code doesn’t need $scope at all anymore!

Conclusion

Make everything a component. If you can’t use 1.5.3 version now, as a preparation make everything a directive — as described in Sane, scalable Angular apps are tricky, but not impossible. Lessons learned from PayPal Checkout written by Daniel Brain where it is one of the advice. Or, you can also use component backport by Todd Motto.

--

--

Radek Anuszewski

Software developer, frontend developer in AltConnect.pl, mostly playing with ReactJS, AngularJS and, recently, BackboneJS / MarionetteJS.