Page 1 of 1

bulk event delegation in jQuery 1.4.2+ Rate Topic: -----

#1 thrca  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 28
  • View blog
  • Posts: 65
  • Joined: 21-January 12

Posted 22 January 2012 - 01:52 AM

Hey there fellow coders! I wanted to take the time to document this because, while it is a simple concept, it took me a while to get the hang of it, and it is extremely powerful and very efficient.
Without wasting any time, let's get to it.

There is always a need for binding event to elements in jQuery, but for this example, I will illustrate with a grid containing several rows, and several columns. In our grid, we will bind events for mouseover, mouseleave, and click, but you are not limited to these events only.

The old way of doing this was to bind to each row in the table, which means if we have an extremely large table, the amount of events we are binding can get quite large.. Wouldn't it be far easier to bind the event to the table instead? jQ1.4.2 gives us just that... the .delegate() method.

Lets build up a stylesheet for our tutorial...
<style>
body {
  font-family: verdana,helvetica,arial;
}
#myGrid {
  border:1px solid #999;
  margin: 10px;
}
#myGrid TR TD {
  padding:3px;
  width: 40px;
  border-left:1px solid #ccc;
  cursor:pointer;
}
#myGrid TR TD:first-child {
  border-left:none;
}
#myGrid TR {
  background-color: #f1f1f1;
}
#myGrid TR:nth-child(odd) {
  background-color: #fdfdfd;
}
#myGrid TR:first-child {
  background-color: #888;
}
#myGrid .hover {
  background-color: #f1f18c;
}
#myGrid .hover:nth-child(odd) {
  background-color: #fdfd8b
}
</style>



And then put our table down below...
<table id="myGrid" cellspacing="0" cellpadding="0">
  <tr>
    <th>&nbsp;</th>
    <th>ID</th>
    <th>Name</th>
    <th>Email</th>
  </tr>
  <tr>
    <td><input name="sample_cb" type="checkbox"/></td>
    <td>1</td>
    <td>Jim</td>
    <td>jim@example.net</td>
  </tr>
  <tr>
    <td><input name="sample_cb" type="checkbox"/></td>
    <td>2</td>
    <td>John</td>
    <td>john@example.net</td>
  </tr>
  <tr>
    <td><input name="sample_cb" type="checkbox"/></td>
    <td>3</td>
    <td>Fred</td>
    <td>fred@example.net</td>
  </tr>
</table>



Since we want some hovering to happen, we want to add the class .hover or .hoverAlt to our rows as we go over them. We could do this in pure CSS3, but that would not demonstrate delegation for this tutorial.
Now, in the old way of jQuery, we would add some id, or use nth-child selectors to bind some mouseover and mouseleave events to each TR. (Or, for the astute minded, one could use the .hover() method)

A quick sample of what the old way would look like...
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script>
  $('tr').hover(function(){
    $(this).addClass('hover');
  },function(){
    $(this).removeClass('hover');
  }); //bind hover function to EVERY TR.  
  //.hover() is identical to .bind('mouseover',function(){}).bind('mouseleave',function(){})
</script>



That works, and its still relatively fast, but this tutorial is about improving the useability of your code.. So lets switch do the newer jQuery framework and do something cool!

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript">
  $(document).ready(function(){
    $('#myGrid').delegate('tr','mouseover mouseleave',function(e) { //delegate events to the #myGrid table for every TR
      var row_index = $(this).index();  //we want to know which row we are on
      var hover_class = 'hover'; //we will use hover for even rows, hoverAlt for odd rows
      if(row_index){ //we dont want to do anything with the header row
        if(e.type == 'mouseover') { //mouseover event fired
          $(this).addClass(hover_class);
        } else if (e.type == 'mouseleave') { //mouseleave event fired
          $(this).removeClass(hover_class);
        }
      }
    });
    $('#myGrid').delegate('td','click',function(e) { //delegate events to the #myGrid table for every TD
      var cell_index = $(this).index();
      var row_index = $(this).parent().index();
      if (e.type == 'click') { //click event fired
        if (e.target.type !== 'checkbox') { //make sure we didnt click a checkbox
          $(':checkbox',$(this).parent()).trigger('click'); //pretend like we clicked the checkbox if we click anywhere in the line
          //alert('We clicked in row '+row_index+' cell '+cell_index);
        }
      }
    });
  });
</script>



Lets break this down so we can understand what is happening here...
  $(document).ready(function(){ //Run this code when the document is loaded and ready to render

    $('#myGrid').delegate('tr','mouseover mouseleave',function(e) { //delegate events to the #myGrid table for every TR
      /*here, we are using delegate to bind a single event to the table '#myGrid' for all tr.  The 2nd argument of delegate indicates that we want to watch the mouseover and mouseleave events, and the final argument is the function*/

      var row_index = $(this).index();  //we want to know which row we are on
/*since we dont want to do anything to the header row, we need to know which row we are on.  This could also be used for doing things only on specific rows, or on rows with a specific class, ie, sub-header rows*/

      if(row_index){ //we dont want to do anything with the header row, which is index 0

        if(e.type == 'mouseover') { //mouseover event fired
          $(this).addClass('hover'); //add the hover class
        } else if (e.type == 'mouseleave') { //mouseleave event fired
          $(this).removeClass('hover'); //remove the hover class
        }
      }
    });



As you may have noticed, I could have easily bound the click event to the tr also, but I wanted to demonstrate something else that can be very useful.
    $('#myGrid').delegate('td','click',function(e) { //delegate events to the #myGrid table for every TD
/* this time, we bound to the td cells, and we can tell both which cell AND which row we are in.  We could do special coloring using mouseover and mouseleave, or something different depending on where we click.  For my purpose, I only care about click, and I am going to toggle a checkbox for selecting the row */

      var cell_index = $(this).index(); //which cell are we in, 0 based index
      var row_index = $(this).parent().index(); //which row are we in, 0 based index
      if (e.type == 'click') { //click event fired
        if (e.target.type !== 'checkbox') { //make sure we didnt click a checkbox
          /* why did we check this?  If not, the event will fire, triggering the stuff below, AND the default event for the checkbox will fire, toggling it's state */
          $(':checkbox',$(this).parent()).trigger('click'); //pretend like we clicked the checkbox if we click anywhere in the line
          //alert('We clicked in row '+row_index+' cell '+cell_index); //this is included for demo purposes.. You can see the cell locations
        }
      }
    });



I hope this gets you started on how to use the .delegate() method, and be sure to think up some creative ways you can use it.. Gone are the days of attaching onclick="" events to every element!

Here is my complete code for this sample:
<style>
body {
  font-family: verdana,helvetica,arial;
}
#myGrid {
  border:1px solid #999;
  margin: 10px;
}
#myGrid TR TD {
  padding:3px;
  width: 40px;
  border-left:1px solid #ccc;
  cursor:pointer;
}
#myGrid TR TD:first-child {
  border-left:none;
}
#myGrid TR {
  background-color: #f1f1f1;
}
#myGrid TR:nth-child(odd) {
  background-color: #fdfdfd;
}
#myGrid TR:first-child {
  background-color: #888;
}
#myGrid .hover {
  background-color: #f1f18c;
}
#myGrid .hover:nth-child(odd) {
  background-color: #fdfd8b
}
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript">
  $(document).ready(function(){
    $('#myGrid').delegate('tr','mouseover mouseleave',function(e) { //delegate events to the #myGrid table for every TR
      var row_index = $(this).index();  //we want to know which row we are on
      var hover_class = 'hover'; //we will use hover for even rows, hoverAlt for odd rows
      if(row_index){ //we dont want to do anything with the header row
        if(e.type == 'mouseover') { //mouseover event fired
          $(this).addClass('hover');
        } else if (e.type == 'mouseleave') { //mouseleave event fired
          $(this).removeClass('hover');
        }
      }
    });
    $('#myGrid').delegate('td','click',function(e) { //delegate events to the #myGrid table for every TD
      var cell_index = $(this).index();
      var row_index = $(this).parent().index();
      if (e.type == 'click') { //click event fired
        if (e.target.type !== 'checkbox') { //make sure we didnt click a checkbox
          $(':checkbox',$(this).parent()).trigger('click'); //pretend like we clicked the checkbox if we click anywhere in the line
          alert('We clicked in row '+row_index+' cell '+cell_index);
        }
      }
    });
  });
</script>
<table id="myGrid" cellspacing="0" cellpadding="0">
  <tr>
    <th>&nbsp;</th>
    <th>ID</th>
    <th>Name</th>
    <th>Email</th>
  </tr>
  <tr>
    <td><input name="sample_cb" type="checkbox"/></td>
    <td>1</td>
    <td>Jim</td>
    <td>jim@example.net</td>
  </tr>
  <tr>
    <td><input name="sample_cb" type="checkbox"/></td>
    <td>2</td>
    <td>John</td>
    <td>john@example.net</td>
  </tr>
  <tr>
    <td><input name="sample_cb" type="checkbox"/></td>
    <td>3</td>
    <td>Fred</td>
    <td>fred@example.net</td>
  </tr>
</table>



Is This A Good Question/Topic? 1
  • +

Replies To: bulk event delegation in jQuery 1.4.2+

#2 thrca  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 28
  • View blog
  • Posts: 65
  • Joined: 21-January 12

Posted 10 March 2012 - 11:38 AM

As of jQuery 1.7+, .delegate() has been superceded by .on()

Here is the structural differences between .delegate() and .on():

$('scope selector').delegate('selector','events',handler);
$('scope selector').on('events','selector',handler);



Therefore, in order to update your code, all you need to do is replace ".delegate" with ".on" and swap your first parameter with your second parameter.

Cheers!

This post has been edited by thrca: 10 March 2012 - 11:39 AM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1