Does Corona SDK allows event delegation?

The answer is no, right? event.target always points the object with attached listener, so there is no way to work out what was clicked after event propagation, true?

Just wondering if I can save some event listeners by listening to the display group instead of individual buttons.

You can certainly listen to a group instead of individual buttons, but you won’t know which button was clicked without either working out in the handler where the touch was or having a listener directly on the buttons. This is not an expensive operation and if you build your buttons in a DRY style you won’t be losing anything at all. Listening for events is not expensive.

Absolutely, if by event-delegation you mean event-bubbling.  You could set up code to enable this style of event handling.

However, what you described doesn’t sound like delegation to me.  It sounds more like you want to know all elements (perhaps in a hiearachy) that would be hit by the touch and in what order.

Actually, you can do this to, via a bubbling technique.

  • OR - 

You want to use a proxy listener (function attached to one object (the proxy) does touch handling for a second object).

I agree w/ Horacebury’s last statement.  Event listening is pretty cheap.  

I’d further add that having tightly coded action specific listeners for individual objects is better than one generic listener that has to discern what to do for a number of ‘child’ objects.

(This isn’t to say you should generate unique code instances for each listener if those listeners do the same thing.)

-- Three re-usable listeners for different types of objects or actions I want -- local function listenerA( self, event ) -- Some unique set of actions end local function listenerB( self, event ) -- Some unique set of actions end local function listenerC( self, event ) -- Some unique set of actions end ... later ... obj1.touch = listenerA obj1:addEventListener( "touch" ) obj2.touch = listenerB obj2:addEventListener( "touch" ) obj3.touch = listenerC obj3:addEventListener( "touch" )

is better than:

local function listenerZ( self, event ) if( type A ) then -- Some unique set of actions for A objects elseif( type B ) -- Some unique set of actions for B objects elseif( type C ) -- Some unique set of actions for C objects end end ... later ... obj1.touch = listenerZ obj1:addEventListener( "touch" ) obj2.touch = listenerZ obj1:addEventListener( "touch" ) obj3.touch = listenerZ obj1:addEventListener( "touch" )

Thx. I don’t have a problem with attaching many listeners. Just a habit coming from my JavaScript and Node.js background.

A question though:

  • Both of you say I can listen to display group, which is true.

  • But I fail to see an easy way to figure out which button I clicked on, when listening to the parent group.

  • Because unlike DOM on the web, Corona SDK event.target doesn’t always point to the actual target being clicked , but the target being handled. In my case, it would be the parent group (ie. tap event has propagated from button to parent group).

  • Which is why I ask my question in the first place, without event.target , event delegation would be difficult (you can hack it by looking at event coordinate, but it will be an overkill).

By the way, the reason I try to do event delegation is because:

You know when passing an object onto  addEventListener , functions on the object with name matching the event name will be used.

I find myself doing this when binding tap listeners:

function Class:tap (event) if event.target.id == 'button1' then self:\_actual\_handler\_for\_button1() elseif event.target.id == 'button2' then self:\_actual\_handler\_for\_button2() end end

But I could refactor my code to have a Class for each button, so we bind the listener there instead of at the button group class.

Either way, I am just wondering about the Corona SDK best practice here.

(In JavaScript there are often many ways to achieve the same thing, all of them flawed in one way or another, you could say I am spoiled by its flexibility…)

You can easily catch touches on one object and send them to another.  

Here is a (weird) example:

local objA = display.newCircle( 100, 100, 20 ) objA.myName = "a" local objB = display.newRect( 100, 200, 40, 40 ) objB.myName = "b" local function onTouch( self, event ) if( event.phase == "ended" ) then print( self.myName, event.target.myName ) end end objB.touch = onTouch objA:addEventListener("touch", objB ) -- touch A, sends touch to B (self is B, target is A)

Can you summarize the situation you have and the problem you’re trying to solve?

Forget about the mechanics of touches and how Corona works versus Javascript.  

Just summarize the problem you’re trying to solve and I (or others) may have some ideas for you.

@roaminggamer

  • Imagine you are defining a ButtonGroup class.

  • where you define ButtonGroup:tap , to handle each button’s tap event.

  • you do that instead of defining handlers for each button, because you can do a simple self.buttonX:addEventListener(‘tap’, self)

But as you shown, you can do a self.button1.tap = handler and do a self.button1:addEventListener(‘tap’) to achieve the same thing. Which I forgot about…

My original question is about event delegation , which is only possible if you can somehow know the original target of the tap event. Per @horacebury suggestion, it’s better I just define listeners for each button…

So I don’t really have a problem at this point… 

You can certainly listen to a group instead of individual buttons, but you won’t know which button was clicked without either working out in the handler where the touch was or having a listener directly on the buttons. This is not an expensive operation and if you build your buttons in a DRY style you won’t be losing anything at all. Listening for events is not expensive.

Absolutely, if by event-delegation you mean event-bubbling.  You could set up code to enable this style of event handling.

However, what you described doesn’t sound like delegation to me.  It sounds more like you want to know all elements (perhaps in a hiearachy) that would be hit by the touch and in what order.

Actually, you can do this to, via a bubbling technique.

  • OR - 

You want to use a proxy listener (function attached to one object (the proxy) does touch handling for a second object).

I agree w/ Horacebury’s last statement.  Event listening is pretty cheap.  

I’d further add that having tightly coded action specific listeners for individual objects is better than one generic listener that has to discern what to do for a number of ‘child’ objects.

(This isn’t to say you should generate unique code instances for each listener if those listeners do the same thing.)

-- Three re-usable listeners for different types of objects or actions I want -- local function listenerA( self, event ) -- Some unique set of actions end local function listenerB( self, event ) -- Some unique set of actions end local function listenerC( self, event ) -- Some unique set of actions end ... later ... obj1.touch = listenerA obj1:addEventListener( "touch" ) obj2.touch = listenerB obj2:addEventListener( "touch" ) obj3.touch = listenerC obj3:addEventListener( "touch" )

is better than:

local function listenerZ( self, event ) if( type A ) then -- Some unique set of actions for A objects elseif( type B ) -- Some unique set of actions for B objects elseif( type C ) -- Some unique set of actions for C objects end end ... later ... obj1.touch = listenerZ obj1:addEventListener( "touch" ) obj2.touch = listenerZ obj1:addEventListener( "touch" ) obj3.touch = listenerZ obj1:addEventListener( "touch" )

Thx. I don’t have a problem with attaching many listeners. Just a habit coming from my JavaScript and Node.js background.

A question though:

  • Both of you say I can listen to display group, which is true.

  • But I fail to see an easy way to figure out which button I clicked on, when listening to the parent group.

  • Because unlike DOM on the web, Corona SDK event.target doesn’t always point to the actual target being clicked , but the target being handled. In my case, it would be the parent group (ie. tap event has propagated from button to parent group).

  • Which is why I ask my question in the first place, without event.target , event delegation would be difficult (you can hack it by looking at event coordinate, but it will be an overkill).

By the way, the reason I try to do event delegation is because:

You know when passing an object onto  addEventListener , functions on the object with name matching the event name will be used.

I find myself doing this when binding tap listeners:

function Class:tap (event) if event.target.id == 'button1' then self:\_actual\_handler\_for\_button1() elseif event.target.id == 'button2' then self:\_actual\_handler\_for\_button2() end end

But I could refactor my code to have a Class for each button, so we bind the listener there instead of at the button group class.

Either way, I am just wondering about the Corona SDK best practice here.

(In JavaScript there are often many ways to achieve the same thing, all of them flawed in one way or another, you could say I am spoiled by its flexibility…)

You can easily catch touches on one object and send them to another.  

Here is a (weird) example:

local objA = display.newCircle( 100, 100, 20 ) objA.myName = "a" local objB = display.newRect( 100, 200, 40, 40 ) objB.myName = "b" local function onTouch( self, event ) if( event.phase == "ended" ) then print( self.myName, event.target.myName ) end end objB.touch = onTouch objA:addEventListener("touch", objB ) -- touch A, sends touch to B (self is B, target is A)

Can you summarize the situation you have and the problem you’re trying to solve?

Forget about the mechanics of touches and how Corona works versus Javascript.  

Just summarize the problem you’re trying to solve and I (or others) may have some ideas for you.

@roaminggamer

  • Imagine you are defining a ButtonGroup class.

  • where you define ButtonGroup:tap , to handle each button’s tap event.

  • you do that instead of defining handlers for each button, because you can do a simple self.buttonX:addEventListener(‘tap’, self)

But as you shown, you can do a self.button1.tap = handler and do a self.button1:addEventListener(‘tap’) to achieve the same thing. Which I forgot about…

My original question is about event delegation , which is only possible if you can somehow know the original target of the tap event. Per @horacebury suggestion, it’s better I just define listeners for each button…

So I don’t really have a problem at this point…