Element Destroyed (a jQuery Special Event)

by Justin Meyer

Element Destroyed (a jQuery Special Event)

Justin Meyer When building jQuery plugins, it's a best practice to provide some way for the user to teardown the plugin, remove any event handlers, and set things back to a good state. Most plugins can get away with waiting for the element to be removed, but more complex plugins listen for events on elements outside the plugin's element (such as the document or window). For these, it's important to know if an element has been removed and to clean up the plugins leftovers.

posted in Development on May 25, 2010 by Justin Meyer

When building jQuery plugins, it’s a best practice to provide some way
for the user to teardown the plugin, remove any event handlers, and set
things back to a good state. Most plugins can get away with waiting for
the element to be removed, but more complex plugins listen for events on
elements outside the plugin’s element (such as the document or window).
For these, it’s important to know if an element has been removed and to
clean up the plugins leftovers.

To solve this problem, JavaScriptMVC adds a special jQuery event. You
can bind to an element’s destroyed event like:

$('.foo').bind("destroyed", function(){
  //teardown here
})

Download
jquery.event.destroyed.js.
Read its
documentation.
View its jQuery plugin
page
.

Use Cases

Destroyed events are very useful for:

  • Plugins that listen for events on window or document events such as
    a contextmenu.
  • Primary plugins that create secondary plugins or elements that need
    to be removed if the primary plugin was removed. EX: a plugin that
    opens a modal.

Example

We’ll use a reusable menu as a demonstration of the power of destroyed
events. View the demo
here.

The reusable menu plugin creates a single menu for all elements that
share the menu. For performance, the menu is cached in the dom and shown
when appropriate. When all elements that share the menu are removed, we
remove the menu.

The plugin also listens for a document click to hide the menu.When the
menu is removed, it removes this event handler by using use a destroyed
event on the menu.

Lets walk through the code step by step.

// create the reuse menu plugin
jQuery.fn.reusemenu = function( options ) {

  // create the menu element and put it in the dom
  var ul = $("<ul/>")
             .addClass("menu")
             .html(options.length ? 
                   "<li>"+options.join("</li><li>")+"</li>" 
                   : ""  )
             .appendTo(document.body),

  // save a reference to our handler so we can remove it
      hideHandler = function(){ 
        ul.find("li").animate({fontSize: 1, padding: 1});
      },

  // save the number of elements that remain
      count = this.length; 

  //hide the menu when the document is clicked
  $(document).click(hideHandler)     

  //remove the hide handler when the 
  //menu is removed
  ul.bind("destroyed", function(){
    $(document).unbind("click",hideHandler )     
  })


  // for each "Show Menu" button
  this.each(function(){

    var me = $(this);

    // position menu on click
    me.click( function(ev) {
      ul.offset({
        top: ev.pageY+20,
        left: ev.pageX+20
      }).find("li").animate({fontSize: 12, padding: 10});
      ev.stopPropagation();
    })

    // if last element, remove menu
    .bind("destroyed", function() {
      count--;
      if(!count){
        ul.remove();
        ul = null;
      }
    })
  })
};

// create a menu
$(".context").reusemenu(["reuse","able","menu"]);

// remove first context menu when clicked
$("#remove").click(function(){
  $(".context:first").remove()
})

Analysis

This demo does more to show how to use destroyed events than to
highlight why to use them. To demonstrate that, a much more complex and
involved demo is necessary. However, with a little imagination, I can
hopefully use this demo to illustrate how destroyed events can isolate
concerns and produce more error free plugins.

Consider how this widget unbound the document click handler. It would
have been easy for the Show Menu button’s destroyed event to unbind the
document click handler. It would have looked like this:

    .bind("destroyed", function() {
      count--;
      if(!count){
        ul.remove();
        $(document).unbind("click",hideHandler ) //added!
        ul = null;
      }
    })

However, what if the created menu was complex and interacted with other
code or plugins? What if those plugins could remove the menu as well?
We’d want to make damn sure that the document click handler was removed!

The destroyed event, and by extension Event Oriented Architecture,
provides this encapsulation.By listening to the menu destroyed event
we’ve made the menu’s clean up code independent of the “Show Me” button
removal code. Thus, any other plugins could remove the menu we created
and we’d be confident that the click handler would be cleaned up.

Hopefully, I’ve shown how, in very small scale, the destroyed event can
be used to make your plugins clean themselves up nicely and cleanly
separate concerns.

Destroyed in JavaScriptMVC

In JavaScriptMVC, controllers organize events, and the destroyed event
is no different. By overwriting a controller’s destroy method, you can
provide any additional cleanup you need.

  destroy: function(){
     this.someChildElement.remove();
     this._super(); 
  }
})

Note that in JavaScriptMVC, destroy is called when the Controller is
removed from an element. This happens if the element is removed from the
page or if controller.destroy() is called. This is a superior pattern
to just using destroyed events as controller automatically provides a
way to remove a plugin from an element without removing the element.

Getting Started with Cordova

Brian Moschelposted in Development on March 26, 2015 by Brian MoschelAt Bitovi, we’re big fans of building applications with web technologies and using build tools to target other platforms like iOS, Android, and desktop. This article will provide a quick guide to getting up and running quickly with Cordova.

Web Application Theory

Justin Meyerposted in Development on June 27, 2014 by Justin MeyerUnderstand the technology and architecture choices Bitovi make and why we make them. What Bitovi does and why.

Contact Us
(312) 620-0386 | contact@bitovi.com
 or cancel