Tap event not updating in Tableview?

I’ve got yet another question. I’m trying to assign a variable to the index of the row so I can use it in a wider scope, but I’m having some issues. Let me show you guys the code first:

function functions.onRowTouch( event ) print("ONROWTOUCH EXECUTING") if event.phase == "tap" or event.phase == "press" then print("ITEM tapped") if saveData.names[event.target.index] ~= nil then editItemNum = event.target.index print("editnum: " .. editItemNum) function functions.pressRow(event) print("ROW NUM: " .. event.target.index) print("EDITNUM = " .. editItemNum) functions.pressItem() return true end event.target:addEventListener("tap", functions.pressRow) end elseif event.phase == "swipeLeft" then print("SWIPING LEFT") tableView:deleteRows({event.target.index}, {slideLeftTransitionTime=450}) table.remove(saveData.names, editItemNum) table.remove(saveData.dates, editItemNum) table.remove(saveData.amounts, editItemNum) loadsave.saveTable(saveData, "payMeBackTable.json") print("ROW DELETED") end end

The code works great for the first time an item gets tapped, but after that “event.target.index” becomes nil because the print statement is not executing anymore. So I tried the following code:

function functions.onRowTouch( event ) print("ONROWTOUCH EXECUTING") if event.phase == "tap" or event.phase == "press" then editItemNum = event.target.index print("editnum: " .. editItemNum) print("ITEM tapped") if saveData.names[event.target.index] ~= nil then function functions.pressRow(event) print("ROW NUM: " .. event.target.index) --editItemNum = index print("EDITNUM = " .. editItemNum) functions.pressItem() return true end event.target:addEventListener("tap", functions.pressRow) end elseif event.phase == "swipeLeft" then print("SWIPING LEFT") tableView:deleteRows({event.target.index}, {slideLeftTransitionTime=450}) table.remove(saveData.names, editItemNum) table.remove(saveData.dates, editItemNum) table.remove(saveData.amounts, editItemNum) loadsave.saveTable(saveData, "payMeBackTable.json") print("ROW DELETED") end end

Note that the assignment of “editItemNum” is placed outside the if saveData… condition. The print statement was executed this time. So let’s say I’ve got 3 items

  • Item1
  • Item2
  • Item3

When I delete the second item, the third item should become item2, that seems pretty obvious. But when I now tap on this item highlighted in red

  • Item1
  • Item2(3)

It still prints that it is item number 3.

So I tried to explain it as well as possible, please let me know if you don’t understand something about my explanation and ofcourse, let me know if you can help me with this problem!

Anyone an idea about what could be wrong?

Can you copy/paste the output of your log file?

So this is the log for deleting the second item when there are 3 items in total:

22:08:35.680  ONROWTOUCH EXECUTING

22:08:35.680  EVENT.TARGET.INDEX: 2

22:08:35.680  editnum: 2

22:08:35.680  ITEM tapped

22:08:35.680  ROW NUM: 2

22:08:35.680  EDITNUM = 2

22:08:35.680  item pressed

22:08:37.601  EDITITEMNUM NAME: alex

After this, the third item in the list goes up in the table and becomes the second and last item. This is the log:

22:08:41.617  ONROWTOUCH EXECUTING

22:08:41.617  EVENT.TARGET.INDEX: 3

22:08:41.617  editnum: 3

22:08:41.617  ITEM tapped

22:08:41.648  ONROWTOUCH EXECUTING

Like you can see, the event.target.index remains 3 instead of shifting to 2. I’m deleting the table with this command: tableView:deleteRows({editItemNum}, {slideLeftTransitionTime=400} ).

Any ideas?

So I’ve been trying to find a fix but still haven’t found one. But after searching for an explanation for this weird behaviour, I found this post: https://forums.coronalabs.com/topic/47689-wrong-positioning-of-rows-in-table-view-when-one-is-deleted/

This is exactly the problem I’m having too! It was a bug in Corona SDK but they said it got fixed a while back, but it’s not… Atleast not in my build: 2016.2907. So Rob (or anyone else), could it be that there is nothing wrong with the code but it’s a bug in Corona?

It could be a bug. I saw you filed a bug report on it.

TableViews are tricky because there is a strong temptation to make one table row = one row of your data.  Consider:

Your Data

  1. Apple

  2. Bananna

  3. Cranberry

  4. Date

  5. EggPlant

When you render the tableView, you should have 5 rows with each of the fruits in it.

But if you delete row two, your tableView now looks like:

  1. Apple

  2. Cranberry

  3. Date

  4. EggPlant

Cranberry is still #3 in your data set, but now #2 in the TableView. I personally always set a value .id which represents that item in my data rather than where it is in my tableView.  Then when I render a tableView I always add my objects to the row’s group itself:

row.title = display.newText(…)

row.deleteButton = widget.newButton(…)

Then if I need to access them in onRowTouch() I don’t need to know what row I’m touching, I have access to them:

event.target.title:setFillColor(1, 0, 0)

I don’t know how much that may or may not help you. But it’s kind of a MVC or Model-View-Controller way of thinking about your data. If you’re not familiar with MVC then:

Model – that’s your data. You should be able to change it as needed and not affect how it’s displayed.

View – this is your tableView. Your data doesn’t care if it’s being displayed in a tableView or some other object. Also your tableView shouldn’t need to know what order your data is in. It just displays what it’s told.

Controller – is the middleware that marries the Model to the View. In this case the controller is the logic driving your :insert() actions and the onRowTouch() function for manipulating the data. This lets you keep the row indexes separate from your data.

The code that makes this work is something like:
 

 for i = 1, #locationChoices do searchTableView:insertRow({ isCategory = isCategory, rowHeight = rowHeight, rowColor = rowColor, lineColor = lineColor, params = { name = locationChoices[i].name, latitude = locationChoices[i].latitude, longitude = locationChoices[i].longitude, id = i }, }) end

I tell the :insertRow() method what the data for the row is. I don’t depend on my for loop’s index value to associate my tableView row to my data row.

Then inside onRowRender():

local function onLocationRowRender( event ) -- Get reference to the row group local row = event.row ---- Get access to the data passed via the :insertRow() row function local params = event.row.params row.rowTitle = display.newText( row, params.name, 20, rowHeight \* 0.5, myData.font, 16 ) if params.selected then row.checkMark = display.newImageRect( row, "images/checkmark.png", 30, 30 ) end ...

Hi Rob,

So, it is not a bug? My bad… And using an id for each row could help but here is the thing. The id will be set at the beginning of the app, if I’d delete a row, the ids of all the rows that come after that won’t update. Or am I missing out on something here? I’m also not really following what’s happening inside the onRowRender() example. I don’t see any use of ids there.

Also, one more question. Can I call the params also in the onRowTouch() function? Or only in the onRowRender() function? Because deleting the row will not trigger onRowRender().

Hi Rob,

just a quick update. I found a work around, but I’m not sure if it’s the most pretty one… This is the code:

function functions.repopulateRows() tableView:deleteAllRows() functions.addAllRows() end

And this is what the “functions.addAllRows()” method looks like:

function functions.addAllRows() if saveData.names[1] ~= nil then defaultNoItemsTxt.alpha = 0 for i=1, #saveData.names do tableView:insertRow({rowColor = {default={1,1,1,0}, over={1,1,1,0}}, lineColor = {1,1,1,0.3}}) end tableView:reloadData() end end

The index numbers are correct because all the rows are deleted and after that reloaded. The solution wasn’t as difficult eventually, but I guess that’s easy to say once you found it…

But thanks for your last post! I’d never used the params parameter, kinda weird to say, in the tableview. And I’m sure that I can use that in the future :smiley:

Have a nice day,

Bram

No, I’m not saying it’s not a bug. I would think we are tracking the row # and that would be the index value. And row 2 should be row 2. I was just giving you a work around to where the row index wasn’t as important.

I frequently delete all the rows and re-add them. Solves a lot of problems.

Okay, thanks Rob!

Anyone an idea about what could be wrong?

Can you copy/paste the output of your log file?

So this is the log for deleting the second item when there are 3 items in total:

22:08:35.680  ONROWTOUCH EXECUTING

22:08:35.680  EVENT.TARGET.INDEX: 2

22:08:35.680  editnum: 2

22:08:35.680  ITEM tapped

22:08:35.680  ROW NUM: 2

22:08:35.680  EDITNUM = 2

22:08:35.680  item pressed

22:08:37.601  EDITITEMNUM NAME: alex

After this, the third item in the list goes up in the table and becomes the second and last item. This is the log:

22:08:41.617  ONROWTOUCH EXECUTING

22:08:41.617  EVENT.TARGET.INDEX: 3

22:08:41.617  editnum: 3

22:08:41.617  ITEM tapped

22:08:41.648  ONROWTOUCH EXECUTING

Like you can see, the event.target.index remains 3 instead of shifting to 2. I’m deleting the table with this command: tableView:deleteRows({editItemNum}, {slideLeftTransitionTime=400} ).

Any ideas?

So I’ve been trying to find a fix but still haven’t found one. But after searching for an explanation for this weird behaviour, I found this post: https://forums.coronalabs.com/topic/47689-wrong-positioning-of-rows-in-table-view-when-one-is-deleted/

This is exactly the problem I’m having too! It was a bug in Corona SDK but they said it got fixed a while back, but it’s not… Atleast not in my build: 2016.2907. So Rob (or anyone else), could it be that there is nothing wrong with the code but it’s a bug in Corona?

It could be a bug. I saw you filed a bug report on it.

TableViews are tricky because there is a strong temptation to make one table row = one row of your data.  Consider:

Your Data

  1. Apple

  2. Bananna

  3. Cranberry

  4. Date

  5. EggPlant

When you render the tableView, you should have 5 rows with each of the fruits in it.

But if you delete row two, your tableView now looks like:

  1. Apple

  2. Cranberry

  3. Date

  4. EggPlant

Cranberry is still #3 in your data set, but now #2 in the TableView. I personally always set a value .id which represents that item in my data rather than where it is in my tableView.  Then when I render a tableView I always add my objects to the row’s group itself:

row.title = display.newText(…)

row.deleteButton = widget.newButton(…)

Then if I need to access them in onRowTouch() I don’t need to know what row I’m touching, I have access to them:

event.target.title:setFillColor(1, 0, 0)

I don’t know how much that may or may not help you. But it’s kind of a MVC or Model-View-Controller way of thinking about your data. If you’re not familiar with MVC then:

Model – that’s your data. You should be able to change it as needed and not affect how it’s displayed.

View – this is your tableView. Your data doesn’t care if it’s being displayed in a tableView or some other object. Also your tableView shouldn’t need to know what order your data is in. It just displays what it’s told.

Controller – is the middleware that marries the Model to the View. In this case the controller is the logic driving your :insert() actions and the onRowTouch() function for manipulating the data. This lets you keep the row indexes separate from your data.

The code that makes this work is something like:
 

 for i = 1, #locationChoices do searchTableView:insertRow({ isCategory = isCategory, rowHeight = rowHeight, rowColor = rowColor, lineColor = lineColor, params = { name = locationChoices[i].name, latitude = locationChoices[i].latitude, longitude = locationChoices[i].longitude, id = i }, }) end

I tell the :insertRow() method what the data for the row is. I don’t depend on my for loop’s index value to associate my tableView row to my data row.

Then inside onRowRender():

local function onLocationRowRender( event ) -- Get reference to the row group local row = event.row ---- Get access to the data passed via the :insertRow() row function local params = event.row.params row.rowTitle = display.newText( row, params.name, 20, rowHeight \* 0.5, myData.font, 16 ) if params.selected then row.checkMark = display.newImageRect( row, "images/checkmark.png", 30, 30 ) end ...

Hi Rob,

So, it is not a bug? My bad… And using an id for each row could help but here is the thing. The id will be set at the beginning of the app, if I’d delete a row, the ids of all the rows that come after that won’t update. Or am I missing out on something here? I’m also not really following what’s happening inside the onRowRender() example. I don’t see any use of ids there.

Also, one more question. Can I call the params also in the onRowTouch() function? Or only in the onRowRender() function? Because deleting the row will not trigger onRowRender().

Hi Rob,

just a quick update. I found a work around, but I’m not sure if it’s the most pretty one… This is the code:

function functions.repopulateRows() tableView:deleteAllRows() functions.addAllRows() end

And this is what the “functions.addAllRows()” method looks like:

function functions.addAllRows() if saveData.names[1] ~= nil then defaultNoItemsTxt.alpha = 0 for i=1, #saveData.names do tableView:insertRow({rowColor = {default={1,1,1,0}, over={1,1,1,0}}, lineColor = {1,1,1,0.3}}) end tableView:reloadData() end end

The index numbers are correct because all the rows are deleted and after that reloaded. The solution wasn’t as difficult eventually, but I guess that’s easy to say once you found it…

But thanks for your last post! I’d never used the params parameter, kinda weird to say, in the tableview. And I’m sure that I can use that in the future :smiley:

Have a nice day,

Bram

No, I’m not saying it’s not a bug. I would think we are tracking the row # and that would be the index value. And row 2 should be row 2. I was just giving you a work around to where the row index wasn’t as important.

I frequently delete all the rows and re-add them. Solves a lot of problems.

Okay, thanks Rob!