InsertRow TableView with Forloop and SQLite data HELP

I need some help with insertRow for Tableview. I have this function that does work, what I am doing is brining back messages that I fill into table view row by row.

It runs and gets my messages per row from my SQLite database. It also fills in the table view rows perfectly fine, but when I scroll down the list and back up in the simulator the rest of the rows at the top change to just one message.

It fills them correctly before I scroll down, but once I do that’s when it breaks.

I attached capture 1 : before scrolling down

capture 2: after scrolling down and coming back up.

any help would be appreciated.

Thank you

local function LoadSavedGame ( event )

    LoadSavedMessages = DB.getAllSavedMessages()
  
    for i = 1, #LoadSavedMessages do

        messageToRender = (LoadSavedMessages[i])
        print( "LoadSavedMessages "…messageToRender)

        tableView:insertRow
        {
            isCategory = isCategory,
            rowHeight = 40,
            rowColor = {default = { 255, 255, 255, 0 },}
  
        }

    end

end

anyone?

Can you post your onRowRender() function?

The other thing you can do is something like this:

 myList:insertRow{ rowHeight = 40, isCategory = false, rowColor = { 1, 1, 1 }, lineColor = { 0.90, 0.90, 0.90 }, params = { message = messageToRender } }

And in your onRowRender function, you can do something like:

local message = event.row.params.message

Then where you draw your message in onRowRender, just used the variable “message” instead of trying to index into your data table. This is the better way.

Hi Rob,

Basically I am trying to do something like the lifeline game. So I have a json table thats going to save the last message number the player received up to, and when they re launch from a cold start part of the logic checks if there is a saved game state if yes, it gets everything from the db saved so far and loads it back to the tableview. once done, game logic continues from last message. 

Thanks for replying. Here is my On row render and tableview code:

– onRender listener for the tableView

local function onRowRender( event )

    local row = event.row

    local rowTitle = display.newText( row, "Row " … row.index … tostring(messageToRender) , 0, 0, nil, 12 )

    --rowTitle:setReferencePoint( display.CenterLeftReferencePoint )

    rowTitle.x = 0

    rowTitle.anchorX = 0

    rowTitle:setFillColor( 5 )

    rowTitle.y = row.contentHeight * 0.5

end

– Create a tableView

 local tableView = widget.newTableView

 {

     left = 5,

     top = 0,

     width = 310,    

     height = 400,

     noLines = true,

     hideBackground = true,

     onRowRender = onRowRender,

     onRowTouch = onRowTouch

 }

Please post your code using the <> button in the bar with Bold, Italic, etc.

You have no control over when onRowRender() is called. The tableView code will call it when it needs to render a row. If rows are off screen they are disposed of to keep memory low. When it’s ready to bring a row on the screen, it calls this function and the row is created and then brought on screen.

Because of this you can’t use global or upvalue variables like messageToRender because it’s value changes as your insert loop runs and it basically only remembers the last item.

There are two ways to handle this. One is to use an array of messageToRender values that are indexed to match the row.index value. The first item in your data array needs to match what you expect the first row of your tableView to be.  Let’s look at an example:

local messagesToRender = {} local function onRowRender( event ) local row = event.row local rowTitle = display.newText( row, "Row " .. row.index .. messagesToRender[row.index] ) , 0, 0, nil, 12 ) --rowTitle:setReferencePoint( display.CenterLeftReferencePoint ) rowTitle.x = 0 rowTitle.anchorX = 0 rowTitle:setFillColor( 5 ) rowTitle.y = row.contentHeight \* 0.5 end

local function LoadSavedGame ( event ) LoadSavedMessages = DB.getAllSavedMessages() for i = 1, #LoadSavedMessages do messagesToRender[i] = (LoadSavedMessages[i]) print( "LoadSavedMessages "..messagesToRender[i]) tableView:insertRow { isCategory = isCategory, rowHeight = 40, rowColor = {default = { 255, 255, 255, 0 },} } end end

This works assuming there is a one-to-one relationship between the data table and the tableView rows. If you start adding category rows in, or you delete data rows in the middle of the table all bets are off.

In programming there is a concept known as MVC (Model View Controller). I don’t personally like the choice of words in the concept, but basically the Model is your database, it’s scheme and other data structures that make up your data. The View is what actually gets displayed to the user. What makes MVC popular is that it’s designed so that you can change the database and you can change the display at any time without having to effect the other. That’s where the C or controller comes in. It’s the code that maps the data to the view.

In this case, your view is the tableView and each of it’s rows. Your data is your database of information. The controller is the loadSavedGame() function basically. Your data doesn’t need to know how onRowRender works. onRowRender doesn’t care how you get the data from the database. You let the controller do the work.

I proposed this a couple of posts back. The tableView:insert() method supports passing in the data **WITH** the insert call. This lets your data be the data (onRowRender needs to not know anything about the LoadSavedMessages table. You include the data with the insert call. Each row now knows specifically what data goes with it.

You’re code might now look like:

local function onRowRender( event ) local row = event.row local messageToRender = event.row.params.messageToDisplay local rowTitle = display.newText( row, "Row " .. row.index .. messageToRender ) , 0, 0, nil, 12 ) rowTitle.x = 0 rowTitle.anchorX = 0 rowTitle:setFillColor( 5 ) rowTitle.y = row.contentHeight \* 0.5 end local function LoadSavedGame ( event ) local LoadSavedMessages = DB.getAllSavedMessages() for i = 1, #LoadSavedMessages do tableView:insertRow { isCategory = isCategory, rowHeight = 40, rowColor = {default = { 255, 255, 255, 0 },}, params = { messageToDisplay = LoadSavedMessages[i] }, } end end

I personally would go with the latter. MVC will simplify your life in the end.

Rob

Thank you Rob that was a very detailed and awesome explanation. I decided to go with the MVC option as you recommended. I am used to the MVC4 concepts from work designing web apps, and it makes perfect sense. Again I can’t thank you enough. I always check every possible way of fixing issues before I post and as always you are all very helpful. Thank you.

anyone?

Can you post your onRowRender() function?

The other thing you can do is something like this:

 myList:insertRow{ rowHeight = 40, isCategory = false, rowColor = { 1, 1, 1 }, lineColor = { 0.90, 0.90, 0.90 }, params = { message = messageToRender } }

And in your onRowRender function, you can do something like:

local message = event.row.params.message

Then where you draw your message in onRowRender, just used the variable “message” instead of trying to index into your data table. This is the better way.

Hi Rob,

Basically I am trying to do something like the lifeline game. So I have a json table thats going to save the last message number the player received up to, and when they re launch from a cold start part of the logic checks if there is a saved game state if yes, it gets everything from the db saved so far and loads it back to the tableview. once done, game logic continues from last message. 

Thanks for replying. Here is my On row render and tableview code:

– onRender listener for the tableView

local function onRowRender( event )

    local row = event.row

    local rowTitle = display.newText( row, "Row " … row.index … tostring(messageToRender) , 0, 0, nil, 12 )

    --rowTitle:setReferencePoint( display.CenterLeftReferencePoint )

    rowTitle.x = 0

    rowTitle.anchorX = 0

    rowTitle:setFillColor( 5 )

    rowTitle.y = row.contentHeight * 0.5

end

– Create a tableView

 local tableView = widget.newTableView

 {

     left = 5,

     top = 0,

     width = 310,    

     height = 400,

     noLines = true,

     hideBackground = true,

     onRowRender = onRowRender,

     onRowTouch = onRowTouch

 }

Please post your code using the <> button in the bar with Bold, Italic, etc.

You have no control over when onRowRender() is called. The tableView code will call it when it needs to render a row. If rows are off screen they are disposed of to keep memory low. When it’s ready to bring a row on the screen, it calls this function and the row is created and then brought on screen.

Because of this you can’t use global or upvalue variables like messageToRender because it’s value changes as your insert loop runs and it basically only remembers the last item.

There are two ways to handle this. One is to use an array of messageToRender values that are indexed to match the row.index value. The first item in your data array needs to match what you expect the first row of your tableView to be.  Let’s look at an example:

local messagesToRender = {} local function onRowRender( event ) local row = event.row local rowTitle = display.newText( row, "Row " .. row.index .. messagesToRender[row.index] ) , 0, 0, nil, 12 ) --rowTitle:setReferencePoint( display.CenterLeftReferencePoint ) rowTitle.x = 0 rowTitle.anchorX = 0 rowTitle:setFillColor( 5 ) rowTitle.y = row.contentHeight \* 0.5 end

local function LoadSavedGame ( event ) LoadSavedMessages = DB.getAllSavedMessages() for i = 1, #LoadSavedMessages do messagesToRender[i] = (LoadSavedMessages[i]) print( "LoadSavedMessages "..messagesToRender[i]) tableView:insertRow { isCategory = isCategory, rowHeight = 40, rowColor = {default = { 255, 255, 255, 0 },} } end end

This works assuming there is a one-to-one relationship between the data table and the tableView rows. If you start adding category rows in, or you delete data rows in the middle of the table all bets are off.

In programming there is a concept known as MVC (Model View Controller). I don’t personally like the choice of words in the concept, but basically the Model is your database, it’s scheme and other data structures that make up your data. The View is what actually gets displayed to the user. What makes MVC popular is that it’s designed so that you can change the database and you can change the display at any time without having to effect the other. That’s where the C or controller comes in. It’s the code that maps the data to the view.

In this case, your view is the tableView and each of it’s rows. Your data is your database of information. The controller is the loadSavedGame() function basically. Your data doesn’t need to know how onRowRender works. onRowRender doesn’t care how you get the data from the database. You let the controller do the work.

I proposed this a couple of posts back. The tableView:insert() method supports passing in the data **WITH** the insert call. This lets your data be the data (onRowRender needs to not know anything about the LoadSavedMessages table. You include the data with the insert call. Each row now knows specifically what data goes with it.

You’re code might now look like:

local function onRowRender( event ) local row = event.row local messageToRender = event.row.params.messageToDisplay local rowTitle = display.newText( row, "Row " .. row.index .. messageToRender ) , 0, 0, nil, 12 ) rowTitle.x = 0 rowTitle.anchorX = 0 rowTitle:setFillColor( 5 ) rowTitle.y = row.contentHeight \* 0.5 end local function LoadSavedGame ( event ) local LoadSavedMessages = DB.getAllSavedMessages() for i = 1, #LoadSavedMessages do tableView:insertRow { isCategory = isCategory, rowHeight = 40, rowColor = {default = { 255, 255, 255, 0 },}, params = { messageToDisplay = LoadSavedMessages[i] }, } end end

I personally would go with the latter. MVC will simplify your life in the end.

Rob

Thank you Rob that was a very detailed and awesome explanation. I decided to go with the MVC option as you recommended. I am used to the MVC4 concepts from work designing web apps, and it makes perfect sense. Again I can’t thank you enough. I always check every possible way of fixing issues before I post and as always you are all very helpful. Thank you.