tl;dr
Application loads modules, refreshes every X minutes, does not destroy module instances on reloading. $scope.$on('$destroy')
does not get called. Modules DDoS API and slow down application. Manual $broadcast
from applicaton controller to trigger a destroy (code below). How to manually unload a controller instance when $scope.$destroy()
gives "current is null" error?
More detailed explanation
I'm currently working on a dashboard style application which uses angularjs modules as widgets. These are being dynamically loaded using ocLazyLoad to reduce application load times. All content comes from a JSON API.
The dashboard reloads it's widget every 30 minutes (update code below), also rebuilding the view. When this happens, the existing widgets do not get destroyed and remain in the memory. Meaning every X minutes they are set to update also continues to happen. Thus when letting the application run for 2 hours, there's 4 instances of the widgets asking for data every X seconds. When the dashboard reloads its widgets, there's no destroy event getting called on the old instances as these are never destroyed.
I've partially fixed this by having the dashboard controller broadcast a destroy event so the running controllers clean up their $timeout
s, however this does obviously not remove the loaded instances of the widgets from the memory. Trying to call $scope.$destroy()
results in a current is null
error, and using the element remove code below.
The question is, how else can I destroy these controllers?
code blocks
Destroy broadcast receiver
$scope.$on("destroy", function () {
console.log("RMA Widget scope received destroy event. Destroying RMA widget");
$scope.$destroy();
});
Remove module (widget) elements
document.querySelectorAll(".widget").forEach((el) => {
el.remove()
});
Loading modules (widgets). $scope.widgets
is used in ng-repeat
in the body.
$scope.widgets = [];
for (let i = 0; i < rqData.data.data.widgets.length; i++) {
const widget = rqData.data.data.widgets[i];
$ocLazyLoad.load('app/' + widget.type + '/module.js');
$scope.widgets.push({
directive : widget.type + '-widget',
module : 'app/' + widget.type + '/module.js',
view : 'app/' + widget.type + '/view.html',
data : Object.assign(widget.widget_id,
{item_id : widget.id, content : widget.content}),
});
}
$scope.timeout.compile = $timeout($ctrl.compileView, 3000);