title: Live Binding Events in jQuery UI Widget Factory using this._on()
body: <p>I am currently developing a cascading tree menu. When a tree item is expanded it creates new <code>&lt;div&gt;</code>'s below it that may also be expanded. I can get the first set of <code>&lt;div&gt;</code>'s to bind and thus expand, but I can't seem to get the newly created div's to bind automatically using the "this._on" method. I'm looking for functionality similar to live(), delegate() and on().</p>
  
  <p>I have posted my code in jsFiddle at <a href="http://jsfiddle.net/vEAhq/" rel="noreferrer">http://jsfiddle.net/vEAhq/</a> .</p>
  
  <p>I set the event binding under the _setupEvents method on line 60.</p>
  
  <p>In review, the elements that are created in the refresh method, called during the _create method bind okay. It's the elements created in the _expand method that do not get bound like I would expect.</p>
  
  <p>Thanks in advance for your time.</p>
  
  <pre class="lang-js prettyprint-override"><code>$.widget( "custom.categoryMenu", {
  
      options: {
          links: null
      },
  
      _create: function() {
          this.refresh();
          this._on('.categoryNavigationExpandIcon', {
              click: function(event) {
                  var $container = $(event.target).parent();
                  if( ($container).data('expanded') === false ) {
                      this._expand($container);
                  } else {
                      this._contract($container);
                  }
              }
          });
      },
  
      refresh: function() {
          var $elm = this.element;
          var $newElem;
          var $itemTree = this.options.links;
          var $itemTreeRoot = sortObj( $itemTree['1'], 'function', true );
  
          this._setupEvents();
  
          $.each( $itemTreeRoot, function( key, value ) {
              var ID = $itemTreeRoot[key];
              var label = key;
              $newElem = $( '&lt;div style="padding:8px 0;"&gt;&lt;/div&gt;' )
                  .data( 'expanded', false )
                  .data( 'id', ID )
                  .data( 'level', 1 )
                  .addClass( 'categoryNavigationLevel1' );
              $( '&lt;div class="categoryNavigationExpandIcon"&gt;&lt;/div&gt;' ).appendTo($newElem);
              $( '&lt;a href="index.cfm?action=products&amp;cat=' + ID + '" rel="?cat=' + ID + '" class="categoryMenuLabel"&gt;' + label + '&lt;/a&gt;' ).appendTo($newElem);
              // Add triangle icons if there are children
              if ($itemTree[ID]) {
                  $($newElem)
                      .find('.categoryNavigationExpandIcon')
                      .addClass('ui-icon')
                      .addClass('ui-icon-triangle-1-e');
              }
              $elm.append($newElem);
          });
      },
  
      _setupEvents: function() {
          var events = {
              click: function( event ) {
                  event.preventDefault();
              }
          };
  
          this._on('.categoryNavigationExpandIcon', {
              click: function(event) {
                  var $container = $(event.target).parent();
                  if( ($container).data('expanded') === false ) {
                      this._expand($container);
                  } else {
                      this._contract($container);
                  }
              }
          });
      },
  
      _expand: function(container) {
          var $elm = this.element;
          var $itemTree = this.options.links;
          var containerLevel = $(container).data('level');
          var containerID = $(container).data('id');
          var newContainerLevel = containerLevel + 1;
  
          var $itemTreeBranch = sortObj( $itemTree[containerID], 'function', true );
  
          $(container)
              .data('expanded', true)
              .find('.ui-icon-triangle-1-e')
              .removeClass('ui-icon-triangle-1-e')
              .addClass('ui-icon-triangle-1-se');
  
          $.each( $itemTreeBranch, function( key, value ) {
              var ID = $itemTreeBranch[key];
              label = key;
              $newElem = $( '&lt;div style="padding:8px 0;"&gt;&lt;/div&gt;' )
                  .data('expanded', false)
                  .data( 'id', ID )
                  .data( 'level', newContainerLevel )
                  .addClass( 'categoryNavigationLevel' + newContainerLevel );
              $( '&lt;div class="categoryNavigationExpandIcon"&gt;&lt;/div&gt;' ).appendTo($newElem);
              $( '&lt;a href="index.cfm?action=products&amp;cat=' + ID + '" rel="?cat=' + ID + '" class="categoryMenuLabel"&gt;' + label + '&lt;/a&gt;' ).appendTo($newElem);
              // Add triangle icons if there are children
              if ($itemTree[ID]) {
                  $($newElem)
                      .find('.categoryNavigationExpandIcon')
                      .addClass('ui-icon')
                      .addClass('ui-icon-triangle-1-e');
              }
              $(container).after($newElem);
          });
      },
  
      _contract: function(container) {
          var containerLevel = $(container).data('level');
          $(container)
              .data( 'expanded', false )
              .find('.ui-icon-triangle-1-se')
              .removeClass('ui-icon-triangle-1-se')
              .addClass('ui-icon-triangle-1-e');
  
          $(container)
              .nextUntil( '.categoryNavigationLevel' + containerLevel )
              .remove();
      },
  
      destroy: function() {
          $.widget.prototype.destroy.call(this);
      }
  
  });
  
  /**
  * Name: Sort Javascript Object
  * Credit: Arne Martin Aurlien
  * URL: http://am.aurlien.net/post/1221493460/sorting-javascript-objects
  */
  sortObj = function(obj, type, caseSensitive) {
      var temp_array = [];
      for (var key in obj) {
          if (obj.hasOwnProperty(key)) {
              if (!caseSensitive) {
                  key = (key['toLowerCase'] ? key.toLowerCase() : key);
              }
              temp_array.push(key);
          }
      }
      if (typeof type === 'function') {
          temp_array.sort(type);
      } else if (type === 'value') {
          temp_array.sort(function(a,b) {
              var x = obj[a];
              var y = obj[b];
              if (!caseSensitive) {
                  x = (x['toLowerCase'] ? x.toLowerCase() : x);
                  y = (y['toLowerCase'] ? y.toLowerCase() : y);
              }
              return ((x &lt; y) ? -1 : ((x &gt; y) ? 1 : 0));
          });
      } else {
          temp_array.sort();
      }
  
      var temp_obj = {};
      for (var i=0; i&lt;temp_array.length; i++) {
          temp_obj[temp_array[i]] = obj[temp_array[i]];
      }
  
      return temp_obj;
  };
  </code></pre>