Sencha Inc. | HTML5 Apps

Blog

Event Delegation in Sencha Touch

November 11, 2010 | Tommy Maintz

Event Delegation in Sencha Touch by Tommy MaintzRecently, we were asked to analyze the performance of an application made with Sencha Touch. One of the main problems we found was the use of inline event handlers on items inside Lists and DataViews. This showed me that although more experienced Ext developers may know how to properly use event delegation, many new developers using Sencha Touch may not. So here, I will give a quick overview of what event delegation is, and how you should take advantage of it in Sencha Touch.

The most common use case for event delegation is probably in Lists. Often you will want to bind a listener to a specific element that exists in each row of a List (for example the avatars in a list of users). Many developers might be inclined to add an inline onclick attribute to each one of these elements. This has a couple of major drawbacks. First and foremost, it means that the browser will use memory for each one of these listeners. It also has a negative impact on the overall performance of the application. Having event listeners on many elements in the DOM generally slows down the rendering of, and interaction with, the page. This is especially the case on mobile devices with limited hardware capabilities.

To avoid this, you should use a technique called event delegation. Event delegation refers to the use of a single event listener on a parent element to listen for events happening on its children. To achieve this, we can rely on the fact that browsers bubble up events to their parents until they reach the window object.

An added benefit to event delegation is the fact that when we add new children to the parent, they will automatically start triggering our events. Also, when you remove children from the parent, you don’t have to clean up all the event listeners to avoid memory leaks. This is actually what happened in the Sencha Touch application that I mentioned at the beginning of the article. Many items in their Lists were being removed, but the inline event handlers weren’t being cleaned up, causing crashes on the iPad.

In Sencha Touch, we provide developers with ways to easily achieve event delegation. Let’s look at a simple scenario. Suppose we have the following DOM structure somewhere on the page:

<ul id="user-list">
    <li><img src="avatars/dave.png"/><h1>David Kaneda</h1></li>
    <li><img src="avatars/ed.png"/><h1>Ed Spencer</h1></li>
    <li><img src="avatars/aaron.png"/><h1>Aaron Conran</h1></li>
    <li><img src="avatars/jamie.png"/><h1>Jamie Avins</h1></li>
</ul>

Using the Element class in Sencha Touch, we will bind a single listener to the ‘user-list’ element that will delegate any clicks made on the avatars. The code would look like the following:

Ext.fly('user-list').on({
    tap: myHandler,
    delegate: 'img'
});

The value for the delegate option is a CSS selector. If we would have put a class on each one of the avatars called ‘avatar’, the value for delegate could have been ‘.avatar’.

In the previous example, we have used a low level API in Sencha Touch to bind our listener. More often, you will want to add the same behavior to items in a higher level widget like a List. Imagine we have a List with a template that generates the same markup as we have shown before. In that case, we can bind our listener like this:

var list = new Ext.List({
    tpl: '<tpl for="."><li><img src="{avatar}" /><h1>{name}</h1></li></tpl>',
    listeners: {
        el: {
            tap: myHandler,
            delegate: 'img'
        }
    }
});

Each Component in Ext supports the listeners configuration. Usually, you will define handlers for custom events like itemtap or selectionchange. Recently, we have also added support for binding DOM events to these components. Lists (like any Component) have a property called ‘el’. This is what we used in our previous example as the Element that we bind our tap handler to. Since List extends Panel, it also has a property called ‘body’, which means that the following listeners configuration would have also worked:

listeners: {
    body: {
        click: myHandler,
        delegate: 'img'
    }
}

This is actually better in this case, since you might have docked items with images inside your List, which would be trigger our listener as well. In general, it is always good practice to choose the lowest parent that contains all the children.

I hope this short article has helped you understand the benefits of event delegation. I have only touched the surface of what is possible with this technique, and I leave it up to you to find more clever uses for this powerful concept.

There are 20 responses. Add yours.

Nickolay Platonov

4 years ago

Good article, thanks. Hopefully it will be included in the ExtJS and Touch docs.

Ara Minosian

4 years ago

JSF integration will be interesting

Nils Dehl

4 years ago

Great articel Tommy *thumps up*

Dowied

4 years ago

Newb question here: Given that events bubble by default, why do we need to do this? Thanks.

gcallaghan

4 years ago

Can you have delegate the same event to multiple elements?

ex.
listeners: {
  body: {
      click: myHandler,
      delegate: ‘.class1’
  },
  body: {
      click: myHandler,
      delegate: ‘.class2’
  }
}

Tommy Maintz

4 years ago

@Dowied
Delegation is not a replacement for event bubbling, but rather a technique that leverages it. Because events bubble, we can listen for an event happening on a higher level element, and delegate the handler to only fire if the event was targeted on a type of element we are interested in.

@gcallaghan
Yes you can! If the handler is the same, you could even do:
listeners: {
  body: {
      click: myHandler,
      delegate: ‘.class1, .class2’
  }
}

Dowied

4 years ago

@Tommy
Thanks for replying- that’s exactly where I am coming from. I’m struggling, with my limited knowledge, to see what this adds…the CSS selection?

Jay Garcia

4 years ago

Great post Tommy.  I hope this others get a chance to understand this better.

Animal

4 years ago

Delegate allows you to pick up events from multiple elements (All of which match a DomQuery selector) with only one handler.

To listen for clicks from both classes of element as you describe, you’d have to use


listeners: {
    body: {
        click: handlerFn,
        delegate: ‘:any(.class1|class2)’
    }
}


Comma-separated selectors don’t work right now.

Tommy Maintz

4 years ago

Thanks Nige. Learned something new today :p

Kiran

4 years ago

‘pinch’ event doesn’t seem to bubble up, when two fingers are on two different child elements of the container(0.97). bubbling up in 0.95

Awesome Bob

4 years ago

Did I read this in the newsletter or do I predict the future?

Dmitriy Pashkevich

4 years ago

Great tip for beginners!

Thomas Alexander

4 years ago

Right post at the right time for me smile

Thomas Alexander

4 years ago

Just have doubt, when used with list how could i get the selected index of list inside tap?

In list itemtap event we get

“itemtap”: function(list, index, item, e){
}

Michael Mullany

4 years ago

@Awesome. We repost some of the newsletter articles in the blog a few weeks after the newsletter since lots of people don’t open their newsletter.

Sim

4 years ago

@Thomas Alexander, did you find the solution to selecting an index of the clicked/tapped item?!?
I’m stuck at the same point!!!!

Thomas Alexander

4 years ago

@Sim

Better to continue in Forum.

You can check below link

http://www.sencha.com/forum/showthread.php?115674-Event-delegation-in-list

Nick

4 years ago

@Tommy—

To follow up on @Animal and @Thomas Alexander, is there a way to bind distinct events to different parts of the XTemplate?  Going back to the “var list” example from above, is there a way to have a response associated with the “tap” event for the avatar image and then a DIFFERENT “tap” response for the <h1> element in the same template?

Thanks in advance!

Florian Dorfbauer

4 years ago

did anyone find an elegant solution to Thomas’ question:
http://www.sencha.com/forum/showthread.php?115674-Event-delegation-in-list
I was wondering if the “itemtap” is worse than the event-delegation-technique?

Comments are Gravatar enabled. Your email address will not be shown.

Commenting is not available in this channel entry.