Unobtrusively change/wrap the onclick event handler in jQuery

In designing a user control that does quite a bit of UI manipulation to an ASP.NET page on the client-side of things, I ran into a bit of trouble in using a 'wrapper' onclick handler for a GridView row onclick event.  I will be putting this user control on many pages and did not want to couple the control to the page, or at least I wanted to minimize that coupling as much as possible.

Ultimately, I was left with two choices:  manually change the server-side injected javascript for the row's onclick event on every page, or find a way to do it in the user control.  The user control uses the jQuery library, so I was in luck.  When I say I want it to be unobtrusive, I mean I want to execute whatever code the row's event handler has been coded to execute, but under the inspection of my user control (i.e. - to only do so conditionally).

My user control injects a new column into the GridView when a certain mode is introduced, which column is purely independent of the rest of the functionality native to the page before the control was placed on it.  This is by design to keep things abstracted.  By default, the GridView's host page would inject code into the row onclick event to pop up a div with some commands to execute.  This may or may not be happening on other pages, and I wanted to handle it when it did, but not care if it did or not.  When a user clicks my new checkbox column,  I didn't want anything else to happen but what I explicitly coded, even though my checkbox was in a row that had a click event handler placed by the parent page.  How do I achieve this, you may ask?

Well, first we must understand the order of execution of event handlers in jQuery, meaning, it's like a queue and each handler gets called in the order in which it was bound to the element (just like you'd expect).  The one caveat to remember is that in the world of web, the explicit 'onclick' event handler always gets called first.  Given these parameters, the theoretical solution became obvious:  move the onclick handler to a bound 'click' handler, after binding it to my own function.  Sound easy?  Well, it kind of is:

$(gridClientID + " tr").each(function (i, v) {
    // bind ours first
    $(this).bind('click', function (e) {
     if ((e.target && $(e.target).parent().hasClass('printcheckboxes')) || (e.srcElement && $(e.srcElement).parent().hasClass('printcheckboxes'))) {
      e.stopImmediatePropagation();
     }
    });
    if ($(this).attr('onclick')) {
     // get the reference
     var curClick = $(this).attr("onclick");
     // bind the referred function after ours
     $(this).bind('click', curClick);
     // clear the function ref from the onclick attribute
     $(this).attr('onclick', '');
    }
   });


The host page uses postbacks to populate the grid, so as long as this is in something like $(document).ready(), it is good to go.  Wish I'd thought of this solution before I tried everything else under the sun...:)  Of course, this only works for explicit 'onclick' handlers, but it still can prove useful.

Comments

Popular posts from this blog

35x Improved T-SQL LevenShtein Distance Algorithm...at a cost

The hidden workings of __doPostBack - Full or Partial Postback?

Facing Death...dum de dum dum