I need to be able to load/unload angular applications dynamically without causing memory leaks. In jQuery you can do $("#elementHoldingMyWidget").remove(); and the proper destruction code gets executed, event handlers are unbound etc.
I've been unable to find anything in the angular docs mentioning the possibility of tearing down an app once it's been bootstrapped.
My 1st attempt was to destroy the rootScope like so:
var rootScope = $("body").scope();
rootScope.$destroy();
But this doesn't seem to be working, and I'm not sure how the injector and services would be cleaned up even if it did.
How should this be done?
To tear down my application without presenting the user with a white page via $('body').empty, I first $delete() the child scopes and then remove all the properties from $rootScope:
/*
* Iterate through the child scopes and kill 'em
* all, because Angular 1.2 won't let us $destroy()
* the $rootScope
*/
var scope = $rootScope.$$childHead;
while (scope) {
var nextScope = scope.$$nextSibling;
scope.$destroy();
scope = nextScope;
}
/*
* Iterate the properties of the $rootScope and delete
* any that possibly were set by us but leave the
* Angular-internal properties and functions intact so we
* can re-use the application.
*/
for(var prop in $rootScope){
if (($rootScope[prop])
&& (prop.indexOf('$$') != 0)
&& (typeof($rootScope[prop]) === 'object')
) {
$rootScope[prop] = null;
}
}
Well, this post:
https://github.com/angular/angular.js/issues/1537#issuecomment-10164971
claims that there is no 'official' app tear down (at the time of writing), but you can just empty the element holding the app like so:
$('body').empty();
If this is not what you are looking for you can go through these steps for a temporary solution to tearing your app down: https://github.com/angular/angular.js/issues/1537#issuecomment-10184033
Using AngularJS 1.4.0, $rootScope.$destroy() is working again (as it was broken in 1.2). Using this permits to switch between several angularJS apps:
var appManager = new function () {
this.currentAppName;
this.currentApp;
this.startApp = function (appContainerId, appName) {
if (this.currentApp) {
this.destroyApp(this.currentApp, this.currentAppName);
}
var appContainer = document.getElementById(appContainerId);
if (appContainer) {
this.currentAppName = appName;
this.currentApp = angular.bootstrap(appContainer, [appName]);
}
}
this.destroyApp = function (app, appName) {
var $rootScope = app.get('$rootScope');
$rootScope.$destroy();
}
}
// Call this when page is ready to rebootsrap app
appManager.startApp('divContainerId', 'app');