newTableView:deleteRow()

I’ve created a tableView via widget.newTableView{}, where onRenderRow = renderRow.

During renderRow(), I’ve successfully added a Delete button via the following code:

in the code below, deleteBtn and tableView are forward-referenced local variables.

------------------------- code in onRowRender method that powers the Delete button

…       

local deleteBtn = display.newImage(row,“images/Tool-Delete.png”,rowRight-72,rowTop+32)

function deleteBtn:touch(event)
  print (“deleteBtn.id=”,deleteBtn.id)
  tableView:deleteRow(deleteBtn.id)
  return true    
end
        
deleteBtn.idx = row.params.i
deleteBtn:addEventListener( “touch”, deleteBtn )
deleteBtn.id = row.index
 row.deleteBtn = deleteBtn

SUCCESSFUL

When the Delete button is clicked, it correctly prints the row.index value; subsequently, the row IS removed via tableView:deleteRow(deleteBtn.id) – where deleteBtn.id = row.index

RUNTIME ERROR

But immediately after the tableView:deleteRow method fires, i get the following run-time error:

attempt to index field ? (a nil value)

stack traceback

?: in function <?:1261>

(tail call): ?

?: in function <?:498>

?: in function <?:221>

The reference to 221 may refer to Line 221 in my setUpDisplay() function that creates the tableView object:

    – Create the tableView widget in setUpDisplay()
    tableView = widget.newTableView
    {
        left = screenLeft,
        top = screenTop + 50,
        width = screenWidth,
        height = 370,
        onRowRender = renderRow,
        onRowTouch = rowTouched,
        listener = tableViewListener,
        hideBackground = true,
        isLocked = false
    }

Line 221 is the EMPTY line after the closing bracket }, above.

QOTD

Can someone suggest what I am doing to create this runtime error, please?

Whole code need to be sampled for me to help you. But i am guessing you are deleting row and then trying to call it or got reference to it still somewhere in code

Dirindon - thanks for the hint. I added code to delete the row, as well, from the array of data feeding tableView. but to no avail. the error re-occurred.

I’m a newbie and attempting to implement the delete Button to code that already runs on a tutorial I’ve taken.

Here’s the entire main.lua file:

+++++++++++++++++++++++++++++++

– This code is for a tutorial from MasteringCoronaSDK.com
– Project: Widgetv2-TableView
– Description: How to use the tableView in the widget 2.0 library
– Version: 1.0
– Managed with http://OutlawGameTools.com
– Copyright 2013 J. A. Whye. All Rights Reserved.

– Graphical assets courtesy: http://glyphish.com

local widget = require(“widget”)
local table = require(“table”)

– most commonly used screen coordinates
– thanks to crawlSpaceLib for initial set
local centerX = display.contentCenterX
local centerY = display.contentCenterY
local screenLeft = display.screenOriginX
local screenWidth = display.contentWidth - screenLeft * 2
local screenRight = screenLeft + screenWidth
local screenTop = display.screenOriginY
local screenHeight = display.contentHeight - screenTop * 2
local screenBottom = screenTop + screenHeight
local screenTopSB = screenTop + display.topStatusBarContentHeight – when status bar is showing
local screenHeightSB = display.contentHeight - screenTopSB
local screenBottomSB = screenTopSB + screenHeightSB

local tableView
local assocTxt
local deleteBtn

local nameData = {
    {name=“James”, gender=“Male”, forl=“First”, rank=1, assoc=“Jars of jams”},
    {name=“John”, gender=“Male”, forl=“First”, rank=2, assoc=“Toilet”},
    {name=“Robert”, gender=“Male”, forl=“First”, rank=3, assoc=“Bank robber”},
    {name=“Michael”, gender=“Male”, forl=“First”, rank=4, assoc=“Rowboat”},
    {name=“William”, gender=“Male”, forl=“First”, rank=5, assoc=“Bow and arrow”},
    {name=“David”, gender=“Male”, forl=“First”, rank=6, assoc=“Sling with a stone in it”},
    {name=“Richard”, gender=“Male”, forl=“First”, rank=7, assoc=“Rich herd of cows”},
    {name=“Charles”, gender=“Male”, forl=“First”, rank=8, assoc=“Char L’s”},
    {name=“Joseph”, gender=“Male”, forl=“First”, rank=9, assoc=“Multi-colored coat”},
    {name=“Thomas”, gender=“Male”, forl=“First”, rank=10, assoc=“Tank engine”},
    {name=“Mary”, gender=“Female”, forl=“First”, rank=1, assoc=“Little lamb with schoolbooks”},
    {name=“Patricia”, gender=“Female”, forl=“First”, rank=2, assoc=“Pet fish”},
    {name=“Linda”, gender=“Female”, forl=“First”, rank=3, assoc=“Tree limb”},
    {name=“Barbara”, gender=“Female”, forl=“First”, rank=4, assoc=“Barbed-wire bra”},
    {name=“Elizabeth”, gender=“Female”, forl=“First”, rank=5, assoc=“Lizard bath”},
    {name=“Jennifer”, gender=“Female”, forl=“First”, rank=6, assoc=“Gin fur”},
    {name=“Maria”, gender=“Female”, forl=“First”, rank=7, assoc=“Marina”},
    {name=“Susan”, gender=“Female”, forl=“First”, rank=8, assoc=“Lazy susan”},
    {name=“Margaret”, gender=“Female”, forl=“First”, rank=9, assoc=“Market”},
    {name=“Dorothy”, gender=“Female”, forl=“First”, rank=10, assoc=“Yellow brick road”},
    {name=“Smith”, gender=“Unknown”, forl=“Last”, rank=1, assoc="Blacksmith’s anvil "},
    {name=“Johnson”, gender=“Unknown”, forl=“Last”, rank=2, assoc=“Toilet with the sun in it”},
    {name=“Williams”, gender=“Unknown”, forl=“Last”, rank=3, assoc=“Well full of yams”},
    {name=“Jones”, gender=“Unknown”, forl=“Last”, rank=4, assoc=“Bones”},
    {name=“Brown”, gender=“Unknown”, forl=“Last”, rank=5, assoc=“UPS truck”},
    {name=“Davis”, gender=“Unknown”, forl=“Last”, rank=6, assoc=“Vest with day of the week on it”},
    {name=“Miller”, gender=“Unknown”, forl=“Last”, rank=7, assoc=“Mill stone”},
    {name=“Wilson”, gender=“Unknown”, forl=“Last”, rank=8, assoc=“Well with the sun in it”},
    {name=“Moore”, gender=“Unknown”, forl=“Last”, rank=9, assoc=“Boat tie-up (mooring)”},
    {name=“Taylor”, gender=“Unknown”, forl=“Last”, rank=10, assoc=“Tailor/seamstress”},
    }

–==============================================================
– Show data associated with tapped row
–==============================================================
local function showData(idx)
    assocTxt.text = nameData[idx].name … " = " … nameData[idx].assoc
    assocTxt.x = assocTxt.origX
end

–==============================================================
– listen for tableView Events
–==============================================================
local function tableViewListener( event )
    local phase = event.phase
    --print(“tableViewListener phase id”, phase)
    if phase == “ended” then
        --tableView:deleteRow(event.target.id)
        print (“TVL target id”,event.target.id)
    end
    if event.limitReached then
        print(event.direction)
    end
end

–==============================================================
– render each row of the tableView
–==============================================================
local function renderRow( event )
    local row = event.row
    --local rowGroup = event.view
    
    – optional variables for easier placement
    local rowWidth = row.contentWidth
    local rowHeight = row.contentHeight
    local rowCenterX = rowWidth/2
    local rowCenterY = rowHeight/2
    local rowLeft = 0
    local rowRight = rowLeft + rowWidth
    local rowTop = 0
    local rowBottom = rowTop + rowHeight
    
    local idx = row.index
    if row.params then
        idx = row.params.idx
    end

    if row.isCategory == nil or row.isCategory then
        local rowTitle = display.newEmbossedText( row, nameData[idx].gender, 0, 0, nil, 16 )
        rowTitle.anchorX = 0
        rowTitle.x = rowLeft + 15
        rowTitle.y = rowCenterY        
    else        
        local bg = display.newImage(row, “images/list-row-lt-press.png”, rowCenterX, rowCenterY)
        – fake it out - now put different color graphic right over the top of that one.
        bg = display.newImage(row, “images/list-row-lt.png”, rowCenterX, rowCenterY)
        row.pressBG = bg
        
        local rowTitle = display.newText( row, nameData[idx].name, 0, 0, “Helvetica”, 16 )
        rowTitle.anchorX = 0
        rowTitle.x = rowLeft + 15
        rowTitle.y = rowCenterY
        rowTitle:setFillColor(0, 14/255, 164/255)
    
        if nameData[idx].rank == 3 then    
            local star = display.newImage(row, “images/star.png”)
            star.x = rowRight - 20
            star.y = rowTop + 15
        end

        --print(nameData[idx].name)
        – make a delete button        
    
        local deleteBtn = display.newImage(row,“images/Tool-Delete.png”,rowRight-72,rowTop+32)

         function deleteBtn:touch(event)
            print (“deleteBtn.id=”,deleteBtn.id)
            tableView:deleteRow(deleteBtn.id)
            table.remove(nameData,idx)
            return true    
        end
        
        deleteBtn.idx = row.params.i
        deleteBtn:addEventListener( “touch”, deleteBtn )
        deleteBtn.id = row.index
        row.deleteBtn = deleteBtn
    end
end

–==============================================================
– handle touches on the row
–==============================================================
local function rowTouched( event )
    local phase = event.phase
    local rowIdx = event.target.index
    local idx = event.target.params.idx

    if phase == “press” then
        event.row.pressBG.alpha = 0
    end
    if phase == “release” then
        event.row.pressBG.alpha = 1
        showData(idx)
        --tableView:deleteRow( rowIdx )
    end
    if phase == “cancelled” then
        event.row.pressBG.alpha = 1
    end
end

–==============================================================
– Set up the screen with background, widgets, etc.
–==============================================================
local function setUpDisplay()
    
    local background = display.newImage( “images/background.png” )
    background.width = screenWidth
    background.height = screenHeight
    background.x = centerX
    background.y = centerY

    – Create the tableView widget
    tableView = widget.newTableView
    {
        left = screenLeft,
        top = screenTop + 50,
        width = screenWidth,
        height = 370,
        onRowRender = renderRow,
        onRowTouch = rowTouched,
        listener = tableViewListener,
        hideBackground = true,
        isLocked = false
    }

    local lastCat = “”
    local idx = 0
    – populate the tableView widget with data
    for i = 1, #nameData do
        local isCategory = false
        local rowHeight = 67 – 67, 84
        local rowColor = { default = { 1, 1, 1 }, }
        local lineColor = { 220/255, 220/255, 200/255 }
        
        idx = idx + 1
        
        if lastCat ~= nameData[i].gender then
            lastCat = nameData[i].gender
            tableView:insertRow
            {
                isCategory = true,
                rowHeight = 24,
                rowColor = { default = { 150/255, 160/255, 180/255 } },
                lineColor = lineColor,
                params = {idx = idx}
            }
        end

        tableView:insertRow
        {
            isCategory = isCategory,
            rowHeight = rowHeight,
            rowColor = rowColor,
            lineColor = lineColor,
            params = {idx = idx}
        }
    end

    – set up text object for later use
    assocTxt = display.newText( “---------”, 0, 0, screenWidth-40, 0, “Helvetica”, 14 )
    assocTxt:setFillColor(0,0,0)
    assocTxt.anchorX = 0
    assocTxt.x = screenLeft + 20
    assocTxt.origX = assocTxt.x
    assocTxt.y = screenBottom - 40
end

setUpDisplay()

+++++++++++++++++++++++++++++++

Thanks for any hints you can throw my way.

Seth

lol the solution is simple here we go

"

         function deleteBtn:touch(event)
            print (“deleteBtn.id=”,deleteBtn.id)
            tableView:deleteRow(deleteBtn.id)
            table.remove(nameData,idx)
            return true    
        end

"

this is called 2 times on event.phase began and ended

so heres a solution swap function: 

should look like this

      function deleteBtn:touch(event)

if event.phase == “began” then

            print (“deleteBtn.id=”,deleteBtn.id)
            tableView:deleteRow(deleteBtn.id)
            table.remove(nameData,idx)
            return true    

end
        end

Edit: I was just lazy, thats why i asked for whole code :slight_smile: could figure it out from your first post.

your a good man, charley brown! thanks bunches, dirindon.

actually, just after your initial post, I went in and did exactly what you did except set the phase==“ended” - but I’m the lazy one now - i didn’t rerun the code.

I appreciate your help which turned into a helpful learning lesson.

Np. Good idea is to always print all arguments passed to function, if you would dig up logTable as almost everything is table based this would be useful for you http://coronalabs.com/blog/2014/09/02/tutorial-printing-table-contents/, you can make general function in separate file for example call it logTable and pass parameters there to see them, if you plan on relasing your project just comment out logTable function and you are set to go :slight_smile:

thanks #2, Irindon - i’ve integrated the table.print function you provided - that is a big “helper” and much more convenient than the primitive print() function. I gained a bit re understanding Lua better with this stumbling block - thanks for removing it and, additionally, polishing the path.

Whole code need to be sampled for me to help you. But i am guessing you are deleting row and then trying to call it or got reference to it still somewhere in code

Dirindon - thanks for the hint. I added code to delete the row, as well, from the array of data feeding tableView. but to no avail. the error re-occurred.

I’m a newbie and attempting to implement the delete Button to code that already runs on a tutorial I’ve taken.

Here’s the entire main.lua file:

+++++++++++++++++++++++++++++++

– This code is for a tutorial from MasteringCoronaSDK.com
– Project: Widgetv2-TableView
– Description: How to use the tableView in the widget 2.0 library
– Version: 1.0
– Managed with http://OutlawGameTools.com
– Copyright 2013 J. A. Whye. All Rights Reserved.

– Graphical assets courtesy: http://glyphish.com

local widget = require(“widget”)
local table = require(“table”)

– most commonly used screen coordinates
– thanks to crawlSpaceLib for initial set
local centerX = display.contentCenterX
local centerY = display.contentCenterY
local screenLeft = display.screenOriginX
local screenWidth = display.contentWidth - screenLeft * 2
local screenRight = screenLeft + screenWidth
local screenTop = display.screenOriginY
local screenHeight = display.contentHeight - screenTop * 2
local screenBottom = screenTop + screenHeight
local screenTopSB = screenTop + display.topStatusBarContentHeight – when status bar is showing
local screenHeightSB = display.contentHeight - screenTopSB
local screenBottomSB = screenTopSB + screenHeightSB

local tableView
local assocTxt
local deleteBtn

local nameData = {
    {name=“James”, gender=“Male”, forl=“First”, rank=1, assoc=“Jars of jams”},
    {name=“John”, gender=“Male”, forl=“First”, rank=2, assoc=“Toilet”},
    {name=“Robert”, gender=“Male”, forl=“First”, rank=3, assoc=“Bank robber”},
    {name=“Michael”, gender=“Male”, forl=“First”, rank=4, assoc=“Rowboat”},
    {name=“William”, gender=“Male”, forl=“First”, rank=5, assoc=“Bow and arrow”},
    {name=“David”, gender=“Male”, forl=“First”, rank=6, assoc=“Sling with a stone in it”},
    {name=“Richard”, gender=“Male”, forl=“First”, rank=7, assoc=“Rich herd of cows”},
    {name=“Charles”, gender=“Male”, forl=“First”, rank=8, assoc=“Char L’s”},
    {name=“Joseph”, gender=“Male”, forl=“First”, rank=9, assoc=“Multi-colored coat”},
    {name=“Thomas”, gender=“Male”, forl=“First”, rank=10, assoc=“Tank engine”},
    {name=“Mary”, gender=“Female”, forl=“First”, rank=1, assoc=“Little lamb with schoolbooks”},
    {name=“Patricia”, gender=“Female”, forl=“First”, rank=2, assoc=“Pet fish”},
    {name=“Linda”, gender=“Female”, forl=“First”, rank=3, assoc=“Tree limb”},
    {name=“Barbara”, gender=“Female”, forl=“First”, rank=4, assoc=“Barbed-wire bra”},
    {name=“Elizabeth”, gender=“Female”, forl=“First”, rank=5, assoc=“Lizard bath”},
    {name=“Jennifer”, gender=“Female”, forl=“First”, rank=6, assoc=“Gin fur”},
    {name=“Maria”, gender=“Female”, forl=“First”, rank=7, assoc=“Marina”},
    {name=“Susan”, gender=“Female”, forl=“First”, rank=8, assoc=“Lazy susan”},
    {name=“Margaret”, gender=“Female”, forl=“First”, rank=9, assoc=“Market”},
    {name=“Dorothy”, gender=“Female”, forl=“First”, rank=10, assoc=“Yellow brick road”},
    {name=“Smith”, gender=“Unknown”, forl=“Last”, rank=1, assoc="Blacksmith’s anvil "},
    {name=“Johnson”, gender=“Unknown”, forl=“Last”, rank=2, assoc=“Toilet with the sun in it”},
    {name=“Williams”, gender=“Unknown”, forl=“Last”, rank=3, assoc=“Well full of yams”},
    {name=“Jones”, gender=“Unknown”, forl=“Last”, rank=4, assoc=“Bones”},
    {name=“Brown”, gender=“Unknown”, forl=“Last”, rank=5, assoc=“UPS truck”},
    {name=“Davis”, gender=“Unknown”, forl=“Last”, rank=6, assoc=“Vest with day of the week on it”},
    {name=“Miller”, gender=“Unknown”, forl=“Last”, rank=7, assoc=“Mill stone”},
    {name=“Wilson”, gender=“Unknown”, forl=“Last”, rank=8, assoc=“Well with the sun in it”},
    {name=“Moore”, gender=“Unknown”, forl=“Last”, rank=9, assoc=“Boat tie-up (mooring)”},
    {name=“Taylor”, gender=“Unknown”, forl=“Last”, rank=10, assoc=“Tailor/seamstress”},
    }

–==============================================================
– Show data associated with tapped row
–==============================================================
local function showData(idx)
    assocTxt.text = nameData[idx].name … " = " … nameData[idx].assoc
    assocTxt.x = assocTxt.origX
end

–==============================================================
– listen for tableView Events
–==============================================================
local function tableViewListener( event )
    local phase = event.phase
    --print(“tableViewListener phase id”, phase)
    if phase == “ended” then
        --tableView:deleteRow(event.target.id)
        print (“TVL target id”,event.target.id)
    end
    if event.limitReached then
        print(event.direction)
    end
end

–==============================================================
– render each row of the tableView
–==============================================================
local function renderRow( event )
    local row = event.row
    --local rowGroup = event.view
    
    – optional variables for easier placement
    local rowWidth = row.contentWidth
    local rowHeight = row.contentHeight
    local rowCenterX = rowWidth/2
    local rowCenterY = rowHeight/2
    local rowLeft = 0
    local rowRight = rowLeft + rowWidth
    local rowTop = 0
    local rowBottom = rowTop + rowHeight
    
    local idx = row.index
    if row.params then
        idx = row.params.idx
    end

    if row.isCategory == nil or row.isCategory then
        local rowTitle = display.newEmbossedText( row, nameData[idx].gender, 0, 0, nil, 16 )
        rowTitle.anchorX = 0
        rowTitle.x = rowLeft + 15
        rowTitle.y = rowCenterY        
    else        
        local bg = display.newImage(row, “images/list-row-lt-press.png”, rowCenterX, rowCenterY)
        – fake it out - now put different color graphic right over the top of that one.
        bg = display.newImage(row, “images/list-row-lt.png”, rowCenterX, rowCenterY)
        row.pressBG = bg
        
        local rowTitle = display.newText( row, nameData[idx].name, 0, 0, “Helvetica”, 16 )
        rowTitle.anchorX = 0
        rowTitle.x = rowLeft + 15
        rowTitle.y = rowCenterY
        rowTitle:setFillColor(0, 14/255, 164/255)
    
        if nameData[idx].rank == 3 then    
            local star = display.newImage(row, “images/star.png”)
            star.x = rowRight - 20
            star.y = rowTop + 15
        end

        --print(nameData[idx].name)
        – make a delete button        
    
        local deleteBtn = display.newImage(row,“images/Tool-Delete.png”,rowRight-72,rowTop+32)

         function deleteBtn:touch(event)
            print (“deleteBtn.id=”,deleteBtn.id)
            tableView:deleteRow(deleteBtn.id)
            table.remove(nameData,idx)
            return true    
        end
        
        deleteBtn.idx = row.params.i
        deleteBtn:addEventListener( “touch”, deleteBtn )
        deleteBtn.id = row.index
        row.deleteBtn = deleteBtn
    end
end

–==============================================================
– handle touches on the row
–==============================================================
local function rowTouched( event )
    local phase = event.phase
    local rowIdx = event.target.index
    local idx = event.target.params.idx

    if phase == “press” then
        event.row.pressBG.alpha = 0
    end
    if phase == “release” then
        event.row.pressBG.alpha = 1
        showData(idx)
        --tableView:deleteRow( rowIdx )
    end
    if phase == “cancelled” then
        event.row.pressBG.alpha = 1
    end
end

–==============================================================
– Set up the screen with background, widgets, etc.
–==============================================================
local function setUpDisplay()
    
    local background = display.newImage( “images/background.png” )
    background.width = screenWidth
    background.height = screenHeight
    background.x = centerX
    background.y = centerY

    – Create the tableView widget
    tableView = widget.newTableView
    {
        left = screenLeft,
        top = screenTop + 50,
        width = screenWidth,
        height = 370,
        onRowRender = renderRow,
        onRowTouch = rowTouched,
        listener = tableViewListener,
        hideBackground = true,
        isLocked = false
    }

    local lastCat = “”
    local idx = 0
    – populate the tableView widget with data
    for i = 1, #nameData do
        local isCategory = false
        local rowHeight = 67 – 67, 84
        local rowColor = { default = { 1, 1, 1 }, }
        local lineColor = { 220/255, 220/255, 200/255 }
        
        idx = idx + 1
        
        if lastCat ~= nameData[i].gender then
            lastCat = nameData[i].gender
            tableView:insertRow
            {
                isCategory = true,
                rowHeight = 24,
                rowColor = { default = { 150/255, 160/255, 180/255 } },
                lineColor = lineColor,
                params = {idx = idx}
            }
        end

        tableView:insertRow
        {
            isCategory = isCategory,
            rowHeight = rowHeight,
            rowColor = rowColor,
            lineColor = lineColor,
            params = {idx = idx}
        }
    end

    – set up text object for later use
    assocTxt = display.newText( “---------”, 0, 0, screenWidth-40, 0, “Helvetica”, 14 )
    assocTxt:setFillColor(0,0,0)
    assocTxt.anchorX = 0
    assocTxt.x = screenLeft + 20
    assocTxt.origX = assocTxt.x
    assocTxt.y = screenBottom - 40
end

setUpDisplay()

+++++++++++++++++++++++++++++++

Thanks for any hints you can throw my way.

Seth

lol the solution is simple here we go

"

         function deleteBtn:touch(event)
            print (“deleteBtn.id=”,deleteBtn.id)
            tableView:deleteRow(deleteBtn.id)
            table.remove(nameData,idx)
            return true    
        end

"

this is called 2 times on event.phase began and ended

so heres a solution swap function: 

should look like this

      function deleteBtn:touch(event)

if event.phase == “began” then

            print (“deleteBtn.id=”,deleteBtn.id)
            tableView:deleteRow(deleteBtn.id)
            table.remove(nameData,idx)
            return true    

end
        end

Edit: I was just lazy, thats why i asked for whole code :slight_smile: could figure it out from your first post.

your a good man, charley brown! thanks bunches, dirindon.

actually, just after your initial post, I went in and did exactly what you did except set the phase==“ended” - but I’m the lazy one now - i didn’t rerun the code.

I appreciate your help which turned into a helpful learning lesson.

Np. Good idea is to always print all arguments passed to function, if you would dig up logTable as almost everything is table based this would be useful for you http://coronalabs.com/blog/2014/09/02/tutorial-printing-table-contents/, you can make general function in separate file for example call it logTable and pass parameters there to see them, if you plan on relasing your project just comment out logTable function and you are set to go :slight_smile:

thanks #2, Irindon - i’ve integrated the table.print function you provided - that is a big “helper” and much more convenient than the primitive print() function. I gained a bit re understanding Lua better with this stumbling block - thanks for removing it and, additionally, polishing the path.