1

I am trying to understand the destruction process of Angular Components a bit more detailed than what I could find in the documentation. I was hoping someone here would be able to answer the following questions:

Are properties on elements in the Component template removed before the event listeners of such elements are removed?

In the destruction process of a Component, when and how does the de-registration of an event listener happen?

Is there any more information available concerning the process of removing event listeners internally in Angular?

MrMalt
  • 42
  • 7

1 Answers1

2

In JavaScript you cannot remove a DOM node per-se. If you have the following DOM tree:

div.children
   span

To "destroy" a span you simply need to remove it from the div.children. If there are no more links pointing to the span element it will be garbage collected. And the same holds true for objects.

Imagine the following structure in Angular:

ComponentA.nodes
   ComponentBElement -> ComponentBClass

Now Angular needs to "destroy" ComponentB. To do that it simply detaches ComponentBElement from the parent ComponentA.nodes. And this is what Angular does, for example, when you execute viewContainerRef.clear():

function execRenderNodeAction(...) {
  const renderer = view.renderer;
  switch (action) {
    ...
    case RenderNodeAction.RemoveChild:
      renderer.removeChild(parentNode, renderNode);
      break; 

Now, suppose Angular added some event listeners to ComponentBElement or its children.

Is there any need to explicitly call removeEventListners? Usually no, because once DOM elements are removed the event listeners are garbage collected as well. However, there's a possibility that a reference to the event listener is captured in some async task or an object that continues to live. This prevents the listener and the DOM from being garbage collected. So Angular ensures that event listeners are removed (in v5 it's DomEventsPlugin.removeEventListener method).

When Angular creates a component view it calls listenToElementOutputs:

function listenToElementOutputs(view, compView, def, el) {
    for (var i = 0; i < def.outputs.length; i++) {
        ...
        var disposable = listenerView.renderer.listen(listenTarget || el, output.eventName, handleEventClosure));
        ((view.disposables))[def.outputIndex + i] = disposable; <------
    }
}

You can see that event is attached using renderer and then the unsubscription callback (disposable) is stored into view.disposables. When Angular destroys a view these disposables are executed and event listeners are removed.:

function [destroyView](view) {
    ...
    if (view.disposables) {
        for (var i = 0; i < view.disposables.length; i++) {
            view.disposables[i](); <----------------
        }
    }

To learn more about views and compilation read:

Max Koretskyi
  • 101,079
  • 60
  • 333
  • 488
  • Thank you for clarifying that a bit for me! Do you also happen to know whether, at some point during this process, properties bound to the view are removed? Does Angular track these the same way as event listeners in views? – MrMalt Oct 18 '17 at 09:27
  • you're welcome, _properties bound to the view_ - what do you mean? can you show an example? – Max Koretskyi Oct 18 '17 at 09:46
  • Sorry, that was a bit unclear. E.g. ``. Here the _border_, _height_ and _width_ class variables are bound to the respective properties (and attribute) of the _table_ element. What I am wondering is if Angular does anything with these bindings when a component is destroyed, and also where I can find more information about how Angular removes them (if it actually does). Thanks!
    – MrMalt Oct 19 '17 at 11:34
  • 1
    @MrMalt, the way these bindings are attached doesn't require any removal. Read [The mechanics of DOM updates in Angular](https://blog.angularindepth.com/the-mechanics-of-dom-updates-in-angular-3b2970d5c03d) to learn more about how bindings are processed – Max Koretskyi Oct 19 '17 at 11:49