Why are scopes not destroyed even after $destroy is triggered?
angularjs, javascript, jquery
Solution
In general, a scope (or any other JS object) can not be cleaned up by the GC if it is still accessible by another JS object.
In practice, in an Angular project that also uses JQuery, this is most likely caused by:
- an Angular service, controller, scope or some other object still having a reference to your scope object
- a reference to your object still exists through a DOM element, probably through an event listener. The DOM element might not be GC-able itself because it is still in the cache of JQuery
Your example, for instance, creates a memory leak.
From your code:
$scope.removeDialog = () ->
console.log "closing"
child.$destroy()
$('.listshell').remove()
return
You do not set `child` to `null` so `$scope.removeDialog` still has access to the scope object referenced by the `child` variable. Therefore, this object can not be GC'ed.
NB: It seems to me that it would be more appropriate to put `removeDialog` on the child scope. Now your example only works because the child scope is not isolated.
Problem
I have made a directive that, when clicked, creates a dialog that is appended to the body using jQuery. The problem is that when the dialog is closed, the scopes are never properly cleaned up. As shown in the picture below 167 ChildScopes are preserved. Which matches the amount of items in the dialog which includes the ng-repeat directive. I attempted to create an extremely simple version of the scenario on Plnkr. To my surprise the scopes ARE in fact being removed on each close in the Plnkr. So something, somewhere in production is causing the scopes to stay alive even after `$destroy` has been called. ``` link: ($scope, $element, $attr) -> $element.on 'click', () -> $scope.$apply () -> child = $scope.$new() template = """<span ng-controller="ListCtrl">...List dialog things...</span>""" compiledTemplate = $compile(template)(child) container = containers.createDialogContainer($element) container.append(compiledTemplate) #cleanup $scope.closeWidget = () -> container.trigger("container_close") return container.on "container_close", ()-> child.$apply () -> child.$destroy() return ``` So here is my question: What can cause a scope to stay alive even after $destroy has been called, triggered and garbage collection performed? For obvious reasons I cannot show you our production code. However the directive in the Plnkr matches the one im debugging sufficiently.