posted by: Joe Osburn - 10.26.2012
Hey Devs, If you know of a better way to handle this particular issue, please share in the comments below!
Even better, you can use Turbolinks now as a gem in your Rails 3.2 project.
$( selector ).click( function()… )
Or, alternatively, the more verbose and modern approach, using jQuery on():
$( selector ).on( 'click', function()… )
Or, in older cases, using bind():
$( selector ).bind( 'click', function()… )
The problem with this method is that your event handlers will need to be attached each time your DOM is modified, such as the case when Turbolinks updates your <body> element without loading the full page. Your document ready function will not fire with Turbolinks.
The solution, with jQuery, is delegated event handling. Delegated event handling works very similarly to regular event handling, with one small change. You provide a top level element, and then provide a search selector for the individual elements to receive the event. When using jQuery on() with delegate events, the event is bound to the top level element, but when it runs, the children of the element are traversed looking for matches for the selector. A very simple way to do this would be to use the document object as the parent element. For example, if we wanted to handle the click events for elements with the class "click_link", we could register a delegated event handler like so:
$( document ).on( 'click', '.click_link', function()… )
Notice the second argument to on(), '.click_link'. This is the selector that is actually going to receive the event, but the DOM tree will be traversed looking for matching selectors, starting with the parent element, on the fly, when the event fires. This has the added benefit of making your code idempotent, and further, can be used in instances where you are modifying your DOM structure on the fly and have new elements created which should handle events. No more binding links in your addItem() function, for example.
Additionally, if you have a lot of elements receiving the event, this approach is faster than binding all of the individual event handlers.
The only downside (that I know of) to this approach is that event propagation may happen more slowly. This means if you stop event propagation (using event.preventDefault() or event.stopPropagation()), it may not occur in time to prevent all the events from firing that you want. This doesn't cause problems for links to '#' which are handled with event.preventDefault(), but it may cause issues in other cases where you have multiple event handlers on one element.
Please leave me any questions or comments. If you know of a better way to handle this particular issue, please share!