Angular.js: Question: why is scope.$destroy not automatically called on directives with isolate scope?

Created on 3 Mar 2016  路  5Comments  路  Source: angular/angular.js

When I have a restrict: 'E' directive with an isolate scope, I am wondering why the $scope.$destroy() would not be called automatically when the element is destroyed?

I have seen a couple articles about this. I just wonder if there is a case that an isolate scope should stay after its element is destroyed?

Assuming it is an isolate scope, would it be a bad idea to include in my directive something like:

element.on('$destroy', function(){
    scope.$destroy();
});
works as expected

Most helpful comment

You don't have to use ngIfs. But if you are compiling and inserting stuff, then you are responsible for cleaning up after you remove that.

You can simply call generatedScope.$destroy() after you remove the element. E.g.:

function parentPostLink(scope, elem) {
  var generatedScope = scope.$new();
  var generatedElement = $compile('...')(generatedScope);

  elem.append(generatedElement);
  ...
  // Some time later
  generatedElement.remove();
  generatedScope.$destroy();
  ...

All 5 comments

Consider a transclude: element directive where element becomes a comment. Events aren't triggered on comment nodes, so your scope would never have been destroyed. I don't think this is something we could generalize, but of course you're free to do this in your own code if necessary.

Explicit scope destruction usually isn't needed except in the case of manual ngIf like behavior, or if you're drawing outside the lines of the normal scope hierarchy.

I would also like to note, that the built-in structural directives do already clean up scopes as needed (e.g. ngIf, ngSwitch, ngInclude, ngView etc).
If you are manually removing component from the DOM (e.g. as part of your custom structural directive), you are responsible for cleaning up the scopes (as @dcherman alreayd mentioned).

@plong0, how are the components removed from the DOM in your situation ?

Ah that makes sense why it couldn't be generalized. Thank you for the replies.

I was using configuration options passed to my directive to generate its children dynamically and then $compile + append() them. So when the base directive is destroyed or the configuration options changed, I would do generatedElement.remove();

I've refactored the directive to use ng-ifs in its template. It's ok for now, but it seems like if the configuration options have many more combinations of attributes I need to apply to the children, the template will end up with a big list of very similar directives with different ng-if condiitions and combinations of attributes.

You don't have to use ngIfs. But if you are compiling and inserting stuff, then you are responsible for cleaning up after you remove that.

You can simply call generatedScope.$destroy() after you remove the element. E.g.:

function parentPostLink(scope, elem) {
  var generatedScope = scope.$new();
  var generatedElement = $compile('...')(generatedScope);

  elem.append(generatedElement);
  ...
  // Some time later
  generatedElement.remove();
  generatedScope.$destroy();
  ...

Closing as it's working as expected.

Was this page helpful?
0 / 5 - 0 ratings