Search code examples
javascripteventsevent-handlingprototypejsdom-events

Do Javascript event listeners need to be removed prior to removing the element they're attached to?


Suppose I have attached a variety of event listeners to various form elements. Later, I want to remove the entire form.

Is it necessary (or suggested) to unregister any event handlers that exist on the form and its elements? If so, what is the easiest way to remove all listeners on a collection of elements? What are the repercussions of not doing so? I'm using Prototype, if it matters.

Here's what I'm actually doing. I have a simple form, like this:

<form id="form">
  <input type="text" id="foo"/>
  <input type="text" id="bar"/>
</form>

I observe various events on the inputs, e.g.:

$('foo').observe('keypress', onFooKeypress);
$('bar').observe('keypress', onBarKeypress);

etc.

The form is submitted via AJAX and the response is a new copy of the form. I replace the old form with a copy of the new one doing something like $('form').replace(newForm). Am I accumulating a bunch of event cruft?


Solution

  • Yeah, a bit. Not enough to be a huge problem, but older versions of IE will leak under those circumstances.

    As of Prototype 1.6.1 (currently in its final release candidate), the library handles this cleanup on page unload. When you use Prototype to add an event observer, it keeps a reference to that element in an array; on page unload, it loops through that array and removes all your observers.

    However, if the user is going to stay on this page for a while, memory usage will accumulate over the life of the page. You have several options:

    1. Listen for events on an ancestor of the form, one that never gets replaced. Then, in your handler, check where the event came from. (i.e., "event delegation")

    2. Explicitly un-register all your calls before calling Element#replace. In your example, you'd do:

      $('foo', 'bar').each(Element.stopObserving);
      

    This is equivalent to calling stopObserving with no arguments, which has the effect of removing all handlers on a given element.

    I would recommend option 1.

    (We've talked about doing automatic listener removal in a future version of Prototype as part of Element#update and Element#replace, but it's a performance trade-off.)