Question on Event Propagation

I have a table view which lists a bunch of things. To manipulate the list(delete & duplicate items), I set it so that another table view with a list of options will show up when you press an item in the table view.

So when I press on an item in the table, a smaller table view with delete and duplicate will show. I made sure to make a mask that encompasses the whole screen and is semitransparent will catch any events outside of this small table view. Added both these items to its own group which will be removed if the mask is clicked or when an option is clicked. Call this the dialog.

So expected behaviour:

Press the item in table -> dialog shows up -> click an option, execute

Problem:

When I click on the dialog it does what I ask it to do (delete or duplicate or cancel if i click the mask) BUT after that, the original table still registers a tap event. I made sure I return true for when you touch/tap any of the dialog’s components so I don’ know why the original table underneath is still registering events.

Maybe there’s something I don’t get about how events propagate?

Incidentally, the reason I thought this would work is because I actually have two display groups on top of each other, both featuring a table view with information. I have successfully implemented a tab bar which switches between the table views and have not experienced any event propagation to the underlying view group (although I do not delete these views after clicking on the table, unlike with the dialog).

Thoughts? Thanks in advance for the help.

Here is the code for the dialog

–Press Dialog

local widget = require “widget”

local const = require “constants”

this = {}

this.render = function( owner )

    local group = display.newGroup()

    

    local mask = display.newRect(0, 0, display.contentWidth, display.contentHeight)

    mask:setFillColor(0, 0, 0, 180)

    local block = function( event )

        if event.phase == “tap” or event.phase == “ended” then

            local e = {

                name = “dialogChoice”,

                choice = “none”

            }

            group:dispatchEvent(e)

            group:removeSelf()

            group = nil

            return true

        elseif event.phase == “began” or event.phase == “press” then

            return true

        end

    end

    mask:addEventListener(“touch”, block)

    mask:addEventListener(“tap”, block)

    

    local function onChoiceTouch( event )

        local phase = event.phase

        local thisChoice = event.target.params.choice

        local params = event.target.params

        if phase == “began” then

            return true

        elseif phase == “tap” then

            local e = { name = “dialogChoice”,

                        choice = thisChoice, 

                        rowId = params.rowId}

            group:dispatchEvent(e)

            group:removeSelf()

            group = nil

            return true

        elseif phase == “press” or phase == “release” then

            return true

        end

        return true

    end

    

    local function renderRows( event )

        local row = event.row

        local params = event.row.params

        

            rowTitle = display.newText(row, params.displayText, 0, 0, nil, const.disFontSize)

            rowTitle.x = row.contentWidth*0.5

            rowTitle.y = row.contentHeight*0.5

        

    end

   local options = {

        left = display.contentWidth*0.1, top = display.contentHeight*0.05, 

        width = display.contentWidth*0.8,

        height = const.tblRowHeight*2,

        onRowRender = renderRows,

        onRowTouch = onChoiceTouch,

        isLocked = true

    }

    local menu = widget.newTableView(options)

    

    local insertRow = function(rowText, rowChoice)

        menu:insertRow{

            isCategory     = false,

            rowHeight     = const.tblRowHeight,

            rowColor     = { 

                default = {100, 100, 100 },

                over     = {100, 100, 100 }},

            lineColor     = const.tblLineColor,

            params         = {displayText = rowText,

                            choice = rowChoice}}

    end

    

    insertRow(“Delete Item”, “delete”)

    insertRow(“Duplicate Item”, “duplicate”)

    

    group:insert( mask )

    group:insert( menu )

    

    return group

end

return this

Bumping

Here is the code for the dialog

–Press Dialog

local widget = require “widget”

local const = require “constants”

this = {}

this.render = function( owner )

    local group = display.newGroup()

    

    local mask = display.newRect(0, 0, display.contentWidth, display.contentHeight)

    mask:setFillColor(0, 0, 0, 180)

    local block = function( event )

        if event.phase == “tap” or event.phase == “ended” then

            local e = {

                name = “dialogChoice”,

                choice = “none”

            }

            group:dispatchEvent(e)

            group:removeSelf()

            group = nil

            return true

        elseif event.phase == “began” or event.phase == “press” then

            return true

        end

    end

    mask:addEventListener(“touch”, block)

    mask:addEventListener(“tap”, block)

    

    local function onChoiceTouch( event )

        local phase = event.phase

        local thisChoice = event.target.params.choice

        local params = event.target.params

        if phase == “began” then

            return true

        elseif phase == “tap” then

            local e = { name = “dialogChoice”,

                        choice = thisChoice, 

                        rowId = params.rowId}

            group:dispatchEvent(e)

            group:removeSelf()

            group = nil

            return true

        elseif phase == “press” or phase == “release” then

            return true

        end

        return true

    end

    

    local function renderRows( event )

        local row = event.row

        local params = event.row.params

        

            rowTitle = display.newText(row, params.displayText, 0, 0, nil, const.disFontSize)

            rowTitle.x = row.contentWidth*0.5

            rowTitle.y = row.contentHeight*0.5

        

    end

   local options = {

        left = display.contentWidth*0.1, top = display.contentHeight*0.05, 

        width = display.contentWidth*0.8,

        height = const.tblRowHeight*2,

        onRowRender = renderRows,

        onRowTouch = onChoiceTouch,

        isLocked = true

    }

    local menu = widget.newTableView(options)

    

    local insertRow = function(rowText, rowChoice)

        menu:insertRow{

            isCategory     = false,

            rowHeight     = const.tblRowHeight,

            rowColor     = { 

                default = {100, 100, 100 },

                over     = {100, 100, 100 }},

            lineColor     = const.tblLineColor,

            params         = {displayText = rowText,

                            choice = rowChoice}}

    end

    

    insertRow(“Delete Item”, “delete”)

    insertRow(“Duplicate Item”, “duplicate”)

    

    group:insert( mask )

    group:insert( menu )

    

    return group

end

return this

Bumping

Hey - did you ever find a solution to this problem? I think I’m experiencing the same thing.

But here’s some temporary code i’m using in the meantime:[lua]

local tableBkg = display.newRect(group, x, y, width, height)

    tableBkg:addEventListener(“touch”, function() return true end)

    tableBkg:addEventListener(“tap”, function() return true end)[/lua]

This tableBkg covers the area right behind the tableView that is being displayed. Because I remove my tableView onRowTouch, I simply remove this tableBkg right after I remove the tableView. Like so:[lua]

local function onRowTouch(event)

    if (event.phase == “tap” or event.phase == “release”) then – this can be whatever

        removeObj(tableView)

        removeObj(tableBkg)

    end

return true end[/lua]

This makes it so that the touch event really does stop after the tableView (even though it should have been earlier by returning true in the onRowTouch function – I’m pretty sure that’s a bug). But yeah so it removes the tableView without any touch events propagating through. But, this is a pretty hacky solution so i’d rather find something more formal / less code.

Hey, to prevent this from happening, I just removed the background that can be clicked to remove the dialog, and in another instance (I didn’t  post it here) I was using a button that would also propagate through.

When I swapped in a display.newRect in place of a widget.newButton, the propagation stopped happening. No idea why that is though, hope that helps.

Hm seems to be something faulty with the widgets then? Yeah I’m not sure.

Is it possible the underlying row is getting the tap at the same time as the original touch or are  you seeing the tap after clearing the 2nd screen?

Also, are you using storyboard?  Have you considered a storyboard overlay scene?  You still have to add a touch and tap handler to the background.

Rob

It only happens after I clear the overlaying dialog. Once I removed the “removeSelf()” call from the block function, the event didn’t propagate through anymore.

I didn’t use storyboard since this was my first project and I thought it was going to be pretty simple.

Hey - did you ever find a solution to this problem? I think I’m experiencing the same thing.

But here’s some temporary code i’m using in the meantime:[lua]

local tableBkg = display.newRect(group, x, y, width, height)

    tableBkg:addEventListener(“touch”, function() return true end)

    tableBkg:addEventListener(“tap”, function() return true end)[/lua]

This tableBkg covers the area right behind the tableView that is being displayed. Because I remove my tableView onRowTouch, I simply remove this tableBkg right after I remove the tableView. Like so:[lua]

local function onRowTouch(event)

    if (event.phase == “tap” or event.phase == “release”) then – this can be whatever

        removeObj(tableView)

        removeObj(tableBkg)

    end

return true end[/lua]

This makes it so that the touch event really does stop after the tableView (even though it should have been earlier by returning true in the onRowTouch function – I’m pretty sure that’s a bug). But yeah so it removes the tableView without any touch events propagating through. But, this is a pretty hacky solution so i’d rather find something more formal / less code.

Hey, to prevent this from happening, I just removed the background that can be clicked to remove the dialog, and in another instance (I didn’t  post it here) I was using a button that would also propagate through.

When I swapped in a display.newRect in place of a widget.newButton, the propagation stopped happening. No idea why that is though, hope that helps.

Hm seems to be something faulty with the widgets then? Yeah I’m not sure.

Is it possible the underlying row is getting the tap at the same time as the original touch or are  you seeing the tap after clearing the 2nd screen?

Also, are you using storyboard?  Have you considered a storyboard overlay scene?  You still have to add a touch and tap handler to the background.

Rob

It only happens after I clear the overlaying dialog. Once I removed the “removeSelf()” call from the block function, the event didn’t propagate through anymore.

I didn’t use storyboard since this was my first project and I thought it was going to be pretty simple.