Dojo in XPages – 18: Event Delegation

We recently saw how to dynamically attach event handlers to DOM elements with dojo.on(). In this post, we’ll see how to use event delegation to set up event handlers that will work on DOM elements that don’t even exist on the page yet. This is powerful logic that is well worth learning.

Dojo in XPages Series

Dojo in XPages — All Blog Posts

Event Binding vs Event Delegation

When you use the examples in the previous post to attach event handlers to DOM elements with dojo.on(), you’re binding that event handling function to the selected element(s) currently on the page. However, if the elements on the page change and new elements are later created, they will not have the event handler bound to them.

Event delegation solves this problem by looking for the desired elements from a higher level (for example, the page body or the window object). This way, if elements are added later that meet the selection criteria, they will still handle the event as desired.

Check out this post by Marky Roden for further explanation.

A Use Case for Event Delegation

A common XPages use case will illustrate the point. Take, for example, a repeat control (that creates a table row for each instance) or view panel that uses a pager.

If you run this code on the page, you will get an event handler that writes a message to the browser console each time a table row is clicked.

dojo.query('tr').on('click', function() {
  console.log ('Clicked Row');

However, if you use the pager to load the next set of rows, then nothing will happen when you click on a row. This is because the event handler was bound to all table rows that existed when the code was run. Once the pager is clicked, those rows were removed and a new set was created on the page.

If you want your function to run any time any row in the view or repeat is clicked, even after paging, you can use event delegation.

The code is very similar, but instead of just specifying an event to handle, you specify also specify a selector to choose the elements as well as the event to handle, in this form selector:event. The other difference is that the first parameter will not be the elements to select, but rather a higher-level element that will contain the elements that you want to handle.

It can take one of these forms:

dojo.on(window.document, [selector[:[event], function() {} );
dojo.query('body').on([selector]:[event], function() {} );

(You can also substitute the name of an existing function in place of the anonymous inline function declaration.)

For example, this will delegate the event by putting the listener on the page body. It will listen for a click event on all tr tags within the page body, regardless of whether they exist now or are created at a later time via client-side code or a partial refresh. (If the entire page is refreshed, then the handler would go away.)

dojo.query('body').on('tr:click', function() {
  console.log('Clicked Row')

The selector uses dojo.query(), so the selector will follow the same rules used for selecting elements with dojo.query().

Here’s another example that will do the same thing, but will save the first call to dojo.query(), so it would seem like it should be more efficient. This uses the dojo.on() method directly (rather than chained to a dojo.query()). Rather than querying an element, you can just set it to the top-level window.document, so it will listen for events on the selected elements anywhere on the page.

dojo.on(window.document, 'tr:click', function() {
  console.log('Clicked Row');

However, if you want to target the listening to a smaller area of the page, you may want to instead use dojo.query() to narrow the scope of listening for the events and elements.

Note that you need to include the dojo.on module on the page if you want to use the dojo.on() method in XPages, but you don’t need to include any modules if you use dojo.query().on().



Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: