TableView using SQLite Database

I’ve been trying to get the TableView working with an SQLite database. I’ve managed to get the data into the TableView but am finding some weird issues:

  1. Whenever I scroll the TableView the rows are re-rended and show data from the very last row returned from the select statement.
  2. My Categories don’t ‘stick’ to the top when scolling.

Could someone please help? My code is below.

Regards,

Trent

local widget = require( “widget” )
local storyboard = require( “storyboard” )
local scene = storyboard.newScene()
local testSQLText = display.newText( “”, 0, 0, native.systemFont, 12)
local serverPath
local myResponse
local evacpath = system.pathForFile( “evaclist.sqlite”, system.TemporaryDirectory )
local evacTableView = nil
local givenname
local familyname
local mobileno
local host
local status
local persontype
local cd

– Our scene
function scene:createScene( event )
    local group = self.view
    
----!!! Listeners !!!----
    – Listen for evacTableView events
    local function evacTableViewListener( event )
        local phase = event.phase

        print( “Event.phase is:”, event.phase )
    end – function
    
    – Handle row rendering
    local function onRowRender( event )
        local phase = event.phase
        local row = event.row
        rowTitle = display.newText( row, givenname…" "…familyname, 0, 0, nil, 16 )
        rowTitle.x = row.x - ( row.contentWidth * 0.5 ) + ( rowTitle.contentWidth * 0.5 ) + 20
        rowTitle.y = row.contentHeight * 0.25
        if event.row.isCategory == true then
            rowTitle.x = display.contentCenterX
            rowTitle.y = row.contentHeight * 0.5
        end --if
        rowTitle:setTextColor( 0, 0, 0 )
        print("rowtitle.x = " …rowTitle.x)
        if cd ~= nil then
            rowCD = display.newText( row, cd, 0, 0, nil, 12 )
            rowCD.x = row.x - ( row.contentWidth * 0.5 ) + ( rowCD.contentWidth * 0.5 ) + 20
            rowCD.y = rowTitle.y + 15
            rowCD:setTextColor( 0, 0, 0 )
            print("rowCD.x = " …rowCD.x)
        end --if
        if mobileno ~= nil then
            rowMobile = display.newText( row, mobileno, 0, 0,  nil, 12 )
            rowMobile.x = row.x - ( row.contentWidth * 0.5 ) + ( rowMobile.contentWidth * 0.5 ) + 20
            rowMobile.y = rowTitle.y + 30
            rowMobile:setTextColor( 0, 0, 0 )
            print("rowmobile.x = " …rowMobile.x)
        end --if
    end – function
    
    – Handle touches on the row
    local function onRowTouch( event )
        local phase = event.phase
        local row = event.target
        if “press” == event.phase then
            print( “Touched row:”, event.target.index )
        end – if
    end – function
    
    – Handles row update
    local function onRowUpdate( event )
        local phase = event.phase
        local row = event.row
    end

    local function networkEvacListener( event )
        if ( event.isError ) then
            testSQLText.text = “Network Error 2!”
        elseif event.phase == “began” then
            testSQLText.text = “Downloading…”
        elseif event.phase == “ended” then
            print(“Received file: evaclist.sqlite”)
            testSQLText.text = “Download Complete!”
            loadSQLList()

        end --if
    end – function
    
    local function networkListener( event )
        if ( event.isError ) then
            testSQLText.text = “Network Error 1!”
        else
            myResponse = event.response

            if tostring(myResponse) == “1” then
                testSQLText.text = “Device not recognised.”
            elseif tostring(myResponse) == “2” then
                testSQLText.text = “Device not registered.”
            else
                testSQLText.text =  “No errors received!”
                print(myResponse)
                local params = {}
                params.progress = true
                network.download( “http://”…serverPath…"/SendEvacuationList?name=" …myResponse, “GET”, networkEvacListener, params, “evaclist.sqlite”, system.TemporaryDirectory)
            end – if
        end – if
    end – function

----!!! Functions !!!----
    function backToMenu()
        transition.to( group, { time = 1000, x = 0 - display.contentWidth, onComplete = function() storyboard.gotoScene( “menu” ); end })
    end – function
    
    function testSQL()
        deviceID = system.getInfo( “deviceID” )
        db = sqlite3.open( path )
        for a in db:nrows(“SELECT * FROM settings”) do
            serverPath = a.ServerPath
        end – for
        db:close()
        if serverPath == nil then
            testSQLText.text = “No Server Path found. Please enter the Server Path in Settings.”
        else
            testSQLText.text = “Connecting… please wait.”
        end – if
        testSQLText.x = display.contentCenterX
        testSQLText.y = display.contentHeight - (testSQLText.contentHeight / 2)
        testSQLText:setTextColor(0,0,0)
        --delete these rows for production
        deviceID = 1
        serverPath = “localhost:85”
        – do it or else
        if serverPath ~= nil then
            network.request( “http://”…serverPath…"/EvacuationListMobile?did=" …deviceID, “GET”, networkListener)
        end – if
    end
    
    function loadSQLList()
        
        evacdb = sqlite3.open( evacpath )
            
        local function onSystemEvent( event )
            if event.type == “applicationExit” then
                evacdb:close()
            end – if
        end – function

        for b in evacdb:nrows(“SELECT * FROM Visitor ORDER BY PersonType, Status, GivenName, FamilyName”) do
            sysID = b.SysID
            givenname = b.GivenName
            familyname = b.FamilyName
            cd = b.CD
            mobileno = b.MobileNo
            host = b.Host
            status = b.Status
            persontype = b.PersonType
            local isCategory =  false
            local rowHeight = 75
            local rowColor =
            {
                default = { 255, 255, 255 },
            }
            local lineColor = { 220, 220, 220 }
                
            if (givenname == “Visitors” and familyname == “On Site”) or (givenname == “Personnel” and familyname == “On Site”) then
                isCategory = true
                rowHeight = 50
                rowColor =
                {
                    default = {212, 212, 212, 200},
                }
            end --if
                
            evacTableView:insertRow
            {
                isCategory = isCategory,
                rowHeight = rowHeight,
                rowColor = rowColor,
                lineColor = lineColor,
            }
        end – for
        
        evacdb:close()
        
    end – function

----!!! Menu and Back Button !!!----

    menuHeaderGroup = display.newGroup ( )
    
    – The gradient used by the title bar
    local titleGradient = graphics.newGradient(
        { 189, 203, 220, 255 },
        { 89, 116, 152, 255 }, “down” )
        
    – Create a title bar
    local titleBar = display.newRect( 0, 0, display.contentWidth, 32 )
    titleBar.y = titleBar.contentHeight / 2
    titleBar:setFillColor( titleGradient )
    menuHeaderGroup:insert(titleBar)    

    
    – Create the title bar text
    local titleBarText = display.newEmbossedText( “visitor id”, 0, 0, native.systemFontBold, 24 )
    titleBarText.x = titleBar.x
    titleBarText.y = titleBar.y
    menuHeaderGroup:insert(titleBarText)
    
    – add back button
    local backButton = widget.newButton
    {
        left = 0,
        top = 0,
        width = 50,
        height = 30,
        default = { 255, 255, 255, 90 },
        over = { 120, 53, 128, 255 },
        fontSize = 12,
        label = “Back”,
        onRelease = backToMenu,
    }
    backButton.x = display.contentWidth - (backButton.contentWidth / 2)

    – Create controls

    evacTableView = widget.newTableView
    {
        top = titleBar.contentHeight,
        width = 320,
        height = 400,
        --backgroundColor = { 255, 255, 255 },

        listener = evacTableViewListener,
        onRowRender = onRowRender,
        onRowTouch = onRowTouch,
        onRowUpdate = onRowUpdate,
    }
    
    group:insert(evacTableView)
    group:insert(menuHeaderGroup)
    group:insert(backButton)

    group:insert(testSQLText)
    group.x = display.contentWidth * 1.5
    transition.to( group, {time = 1000, x = 0, onComplete = testSQL})

end – function

scene:addEventListener( “createScene” )

function scene:destroyScene( event )
    print( “Called when scene is unloaded.” )
    evacdb:close()
end

scene:addEventListener( “destroyScene” )

return scene
 

Some great code in there. I think your issue is in the for loop where you allocate the results of your sql select into a single variable set. OnRender first time works because it gets each row’s data one at a time through the variable set but when time comes to reRender due to moving up & down the for loop does not get all the records again. Here’s what I would do… 

Create a table to hold all the records read from the sql statement. 

Keep your current for loop but modify it to look somewhat like this : 

local evacRecs = {} – watch out for scoping. Possibly needs to be at the top of your code. 

       local idx = 0 – counter used to insert rows into your table holding the evac records.

        for b in evacdb:nrows(“SELECT * FROM Visitor ORDER BY PersonType, Status, GivenName, FamilyName”) do

           idx = idx + 1
            evacRecs[idx].sysID = b.SysID

            evacRecs[idx].givenname = b.GivenName

            evacRecs[idx].familyname = b.FamilyName

           …

Then modify your onRowRender to look somewhat like this

 if cd ~= nil then
            rowCD = display.newText( row, evacRecs[row.index].cd, 0, 0, nil, 12 )

This should pull the right record out of your table for a given row (using row.index as index on your table). 

Hope this helps. 

Hi ksan,

Thank you very much, that got it working. I had tried putting the results into a table before but didn’t realise I needed to use row.index so I was getting the same results.

One last thing is that my Categories are still not sticking to the top of the window when scrolling. I’ve attached an image that shows this. The ‘Personnel’ Category should be showing at the top of the window in the image but it just scrolls away like a normal row. How can I get the Categories to stick?

Regards,

Trent

Glad to hear you got it working. The categories not sticking issue… I think there was a bug causing this at some point which was fixed somewhere along the way. Maybe its not in the most recent public build. Can’t recall. Did you try building with the open source version of the widgets library? See stickied post at the top of this sub-forum. 

Great thank you ksan!

You’re most welcome. Hope that gets all working for you. Let us know how it goes! Best of luck.

Hmmm… the widgets sample works with the latest open source build, but in my app the Categories still don’t stick! I’ve tested that row.isCategory == true in the rowRender listener and the isCategory value is being set correctly.

Any ideas?

Regards,

Trent

I think I know what’s going on. Will try to review your code again but you can look for this as well. Does the second category appear at all? My guess is first category is drawn on screen and then flows out of view when its time to bring in the second category and lock it up at the top of the screen. Review your onRowRender to see how your code works when row.isCategory == true. Hope this helps. 

Edit 

You have the following in your ORR

        if event.row.isCategory == true then

            rowTitle.x = display.contentCenterX
            rowTitle.y = row.contentHeight * 0.5
        end --if
        rowTitle:setTextColor( 0, 0, 0 )
        print("rowtitle.x = " …rowTitle.x)

I think you need to pull the code that puts the category text on screen into that if then end box. Can’t see where that is. See if you can figure it out and if not please post an updated copy of your code.

Yes the second Cateogry does appear - image attached of how it looks when first loaded. Sorry I’m very new at Corona so I wouldn’t even know what to look for…

Regards,

Trent

EDIT - Didn;t realise you had posted just before - I’ll check my code with what you have suggested and will get back to you.

Sorry ksan, I’m not sure what to be looking for. Here is my updated code - really appreciate the help.

local widget = require( “widgetTX” )
local storyboard = require( “storyboard” )
local scene = storyboard.newScene()

– Our scene
function scene:createScene( event )
    local group = self.view
    
    local testSQLText = display.newText( “”, 0, 0, native.systemFont, 12)
    local serverPath
    local myResponse
    local evacpath = system.pathForFile( “evaclist.sqlite”, system.TemporaryDirectory )
    local evacTableView = nil
    local evacRecs = {}
    local idx = 0
    
----!!! Listeners !!!----
    – Listen for evacTableView events
    local function evacTableViewListener( event )
        local phase = event.phase

        print( “Event.phase is:”, event.phase )
    end – function
    
    – Handle row rendering
    local function onRowRender( event )
        local phase = event.phase
        local row = event.row
        rowTitle = display.newText( row, evacRecs[row.index].givenname…" "…evacRecs[row.index].familyname, 0, 0, nil, 16 )
        if row.isCategory == true then
            rowTitle.x = display.contentCenterX
            rowTitle.y = row.contentHeight * 0.5
        else
            rowTitle.x = row.x - ( row.contentWidth * 0.5 ) + ( rowTitle.contentWidth * 0.5 ) + 20
            rowTitle.y = row.contentHeight * 0.25
        end --if
        rowTitle:setTextColor( 0, 0, 0 )
        print("rowtitle.x = " …rowTitle.x)
        if evacRecs[row.index].cd ~= nil then
            rowCD = display.newText( row, evacRecs[row.index].cd, 0, 0, nil, 12 )
            rowCD.x = row.x - ( row.contentWidth * 0.5 ) + ( rowCD.contentWidth * 0.5 ) + 20
            rowCD.y = rowTitle.y + 15
            rowCD:setTextColor( 0, 0, 0 )
            print("rowCD.x = " …rowCD.x)
        end --if
        if evacRecs[row.index].mobileno ~= nil then
            rowMobile = display.newText( row, evacRecs[row.index].mobileno, 0, 0,  nil, 12 )
            rowMobile.x = row.x - ( row.contentWidth * 0.5 ) + ( rowMobile.contentWidth * 0.5 ) + 20
            rowMobile.y = rowTitle.y + 30
            rowMobile:setTextColor( 0, 0, 0 )
            print("rowmobile.x = " …rowMobile.x)
        end --if
    end – function
    
    – Handle touches on the row
    local function onRowTouch( event )
        local phase = event.phase
        local row = event.target
        if “press” == event.phase then
            print( “Touched row:”, event.target.index )
        end – if
    end – function
    
    – Handles row update
    local function onRowUpdate( event )
        local phase = event.phase
        local row = event.row
    end

    local function networkEvacListener( event )
        if ( event.isError ) then
            testSQLText.text = “Network Error 2!”
        elseif event.phase == “began” then
            testSQLText.text = “Downloading…”
        elseif event.phase == “ended” then
            print(“Received file: evaclist.sqlite”)
            testSQLText.text = “Download Complete!”
            loadSQLList()

        end --if
    end – function
    
    local function networkListener( event )
        if ( event.isError ) then
            testSQLText.text = “Network Error 1!”
        else
            myResponse = event.response

            if tostring(myResponse) == “1” then
                testSQLText.text = “Device not recognised.”
            elseif tostring(myResponse) == “2” then
                testSQLText.text = “Device not registered.”
            else
                testSQLText.text =  “No errors received!”
                print(myResponse)
                local params = {}
                params.progress = true
                network.download( “http://”…serverPath…"/SendEvacuationList?name=" …myResponse, “GET”, networkEvacListener, params, “evaclist.sqlite”, system.TemporaryDirectory)
            end – if
        end – if
    end – function

----!!! Functions !!!----
    function backToMenu()
        transition.to( group, { time = 1000, x = 0 - display.contentWidth, onComplete = function() storyboard.gotoScene( “menu” ); end })
    end – function
    
    function testSQL()
        deviceID = system.getInfo( “deviceID” )
        db = sqlite3.open( path )
        for a in db:nrows(“SELECT * FROM settings”) do
            serverPath = a.ServerPath
        end – for
        db:close()
        if serverPath == nil then
            testSQLText.text = “No Server URL found. Please enter the Server URL in Settings.”
        else
            testSQLText.text = “Connecting… please wait.”
        end – if
        testSQLText.x = display.contentCenterX
        testSQLText.y = display.contentHeight - (testSQLText.contentHeight / 2)
        testSQLText:setTextColor(0,0,0)
        --delete these rows for production
        deviceID = 1
        serverPath = “localhost:85”
        – do it or else
        if serverPath ~= nil then
            network.request( “http://”…serverPath…"/EvacuationListMobile?did=" …deviceID, “GET”, networkListener)
        end – if
    end
    
    function loadSQLList()
        
        evacdb = sqlite3.open( evacpath )
            
        local function onSystemEvent( event )
            if event.type == “applicationExit” then
                evacdb:close()
            end – if
        end – function

        for b in evacdb:nrows(“SELECT * FROM Visitor ORDER BY PersonType, Status, GivenName, FamilyName”) do
            idx = idx + 1
            evacRecs[idx] = {}
            evacRecs[idx].sysID = b.SysID
            evacRecs[idx].givenname = b.GivenName
            evacRecs[idx].familyname = b.FamilyName
            evacRecs[idx].cd = b.CD
            evacRecs[idx].mobileno = b.MobileNo
            evacRecs[idx].host = b.Host
            evacRecs[idx].status = b.Status
            evacRecs[idx].persontype = b.PersonType
            local isCategory =  false
            local rowHeight = 75
            local rowColor =
            {
                default = { 255, 255, 255 },
                over = { 0, 174, 239 },
            }
            local lineColor = { 220, 220, 220 }
                
            if (evacRecs[idx].givenname == “Visitors” and evacRecs[idx].familyname == “On Site”) or (evacRecs[idx].givenname == “Personnel” and evacRecs[idx].familyname == “On Site”) then

                isCategory = true
                rowHeight = 50
                rowColor =
                {
                    default = {212, 212, 212, 200},
                }
            end --if
                
            evacTableView:insertRow
            {
                isCategory = isCategory,
                rowHeight = rowHeight,
                rowColor = rowColor,
                lineColor = lineColor,
            }
        end – for
        
        evacdb:close()
        
    end – function

----!!! Controls !!!----    
    – add back button
    local backButton = widget.newButton
    {
        left = 0,
        top = 0,
        width = 50,
        height = 30,
        default = { 255, 255, 255, 90 },
        over = { 120, 53, 128, 255 },
        fontSize = 12,
        label = “Back”,
        onRelease = backToMenu,
    }
    backButton.x = display.contentWidth - (backButton.contentWidth / 2)

    evacTableView = widget.newTableView
    {
        top = 32,
        width = 320,
        height = 400,
        listener = evacTableViewListener,
        onRowRender = onRowRender,
        onRowTouch = onRowTouch,
        onRowUpdate = onRowUpdate,
    }
    
    group:insert(evacTableView)
    group:insert(testSQLText)
    group.x = display.contentWidth * 1.5
    transition.to( group, {time = 1000, x = 0, onComplete = testSQL})

end – function

scene:addEventListener( “createScene” )

function scene:destroyScene( event )
    print( “Called when scene is unloaded.” )

end

scene:addEventListener( “destroyScene” )

return scene
 

I think I’ve got it. I think your code is working as it is expected and I think your data is the problem. I might be totally off but I think the following tells me 

 if (evacRecs[idx].givenname == “Visitors” and evacRecs[idx].familyname == “On Site”) or (evacRecs[idx].givenname == “Personnel” and evacRecs[idx].familyname == “On Site”) then

that you are creating a fake record with givenname = “Visitors” and all records following this record are expected to be shown as Visitors until you have another fake record where givenname = “Personnel”. Is this right?

If my hunch is correct I’m afraid you need to fix your data. Each row of people should have a field where their type is stored (ie are they each a Visitor or Personnel). At first I thought your personType field would contain precisely this information but the more I look at your code the more I got suspicious of how you are determining the categories with the if then statement I copied above. 

Let me know if I’m on the right track and we can discuss how you can fix this. 

Regards,

Kerem

Yes that’s exactly right. I did it that way because I couldn’t think of another way at the time to figure out how to insert the Categories.

Would it better to use two sql tables - 1 for visitors (person type 1) and 1 for personnel (person type 2), then do a for loop on both tables?

Ok. We’re making progress. I’m happy to see we are getting to the bottom of this.

What info do you hold in the field called personType? 

You definitely want one table. Basic database rule. Each type of data element should be in one table only to be differentiated with a field such as your personType. So all data about people should be in one table.

Ideally you would normalize the nature of person (ie Visitor or Personnel) and keep a personType code in your person table. Say 1 = Personnel and 2 = Visitor. In this setup you would keep your possible personTypes in a separate table where the keyfield would be the 1, 2 etc matching whats in your first table and then a personTypeText field would contain your long text (ie Visitor, Personnel etc)… The reason its done this way is to make each record conserve less memory or diskspace and also have faster queries. Select * from xyz where personType = 1 etc works much faster than Select * from xyz where personType = “Visitor” etc…

But in a mobile app with a small number of records you probably would be better off keeping the actual text in the main person table. 

So to summarize, you want to use either your existing personType field or a new field to mark each person record with either Visitor or Personnel. You want to get rid of those fake records. Then you will need to revise your code a little to pick the changes in person type and call a specific insertRow with isCategory = true when you detect the category change. There is a trick there as you will most likely loose one record each time the category changes but we can discuss that next.

Now you have some homework! Have fun!

Ok no worries! PersonType is already set to either 1 or 2 depending, so it’s just figuring out how to insert the Category rows which is where I was stuck before doing it the above way.

What’s this trick you mention??? :slight_smile:

Regards,

Trent

Your data set needs to be ordered by your categories and I see that it is so thats good.

What you need is a little variable to track the current personType. You need to get rid of : 

if (evacRecs[idx].givenname == “Visitors” and evacRecs[idx].familyname == “On Site”) or (evacRecs[idx].givenname == “Personnel” and evacRecs[idx].familyname == “On Site”) then

and something like the following there :

                 if thisPersonType ~= evacRecs[idx].persontype then – declare local thisPersonType somewhere up above.

                            thisPersonType ~= evacRecs[idx].persontype – This is just to keep track of current personType and call insertRow each time personType change.

                            --now insert the category                                

                            tableView:insertRow {

                                isCategory = true,

                                rowHeight = rowCategoryHeight,

                                rowColor = rowCategoryColor,

                                lineColor = lineColor,

                            }

                    end  

this will go and insert the category. The trick is to call 

                            tableView:insertRow {

                                isCategory = false,

                                rowHeight = rowHeight,

                                rowColor = rowColor,

                                lineColor = lineColor,

                            }

again while still in the same loop cycle so that the record itself also gets inserted into a new row in the tableView. Otherwise you will miss one person each time personType changes.

You have one more problem now. row.index used on your ORR will be out of sync with the data table since the tableView now has extra rows for the category lines. You can deal with this by maintaining another counter in the for loop that calls the insertRows. I’ll let you figure that one out as a Lua learning challenge!  :slight_smile:

Good luck. Have fun.

Ok cool, thank you ksan. I’ll let you know how I go :slight_smile:

Regards,

Trent

You’re most welcome. Look forward to hearing your good news! 

Unfortunately I can’t figure out how to setup the counter for fixing the out of sync data :frowning:

So that means you did get your categories to show & stick now. All ok with that? If so post another set of code so I can see where you are. I will see if I can give you some more help for that last issue. 

I just ran into errors… First row renders with Category name then no other rows render at all. Code is below:

local isPersonType = 0

    local function onRowRender( event )
        local phase = event.phase
        local row = event.row

        if row.isCategory == true then
            if thisPersonType == 1 then
                rowTitle = display.newText( row, “Visitors”, 0, 0, nil, 16 )
            elseif thisPersonType == 2 then
                rowTitle = display.newText( row, “Personnel”, 0, 0, nil, 16 )
            end --if
            rowTitle.x = display.contentCenterX
            rowTitle.y = row.contentHeight * 0.5
        else
            rowTitle = display.newText( row, evacRecs[row.index].givenname…" "…evacRecs[row.index].familyname, 0, 0, nil, 16 )
            rowTitle.x = row.x - ( row.contentWidth * 0.5 ) + ( rowTitle.contentWidth * 0.5 ) + 20
            rowTitle.y = row.contentHeight * 0.25
        end --if
        rowTitle:setTextColor( 0, 0, 0 )
        print("rowtitle.x = " …rowTitle.x)
        if evacRecs[row.index].cd ~= nil then
            rowCD = display.newText( row, evacRecs[row.index].cd, 0, 0, nil, 12 )
            rowCD.x = row.x - ( row.contentWidth * 0.5 ) + ( rowCD.contentWidth * 0.5 ) + 20
            rowCD.y = rowTitle.y + 15
            rowCD:setTextColor( 0, 0, 0 )
            print("rowCD.x = " …rowCD.x)
        end --if
        if evacRecs[row.index].mobileno ~= nil then
            rowMobile = display.newText( row, evacRecs[row.index].mobileno, 0, 0,  nil, 12 )
            rowMobile.x = row.x - ( row.contentWidth * 0.5 ) + ( rowMobile.contentWidth * 0.5 ) + 20
            rowMobile.y = rowTitle.y + 30
            rowMobile:setTextColor( 0, 0, 0 )
            print("rowmobile.x = " …rowMobile.x)
        end --if
    end – function

    function loadSQLList()
        
        evacdb = sqlite3.open( evacpath )
            
        local function onSystemEvent( event )
            if event.type == “applicationExit” then
                evacdb:close()
            end – if
        end – function

        for b in evacdb:nrows(“SELECT * FROM Visitor ORDER BY PersonType, Status, GivenName, FamilyName”) do
            idx = idx + 1
            evacRecs[idx] = {}
            evacRecs[idx].sysID = b.SysID
            evacRecs[idx].givenname = b.GivenName
            evacRecs[idx].familyname = b.FamilyName
            evacRecs[idx].cd = b.CD
            evacRecs[idx].mobileno = b.MobileNo
            evacRecs[idx].host = b.Host
            evacRecs[idx].status = b.Status
            evacRecs[idx].persontype = b.PersonType
            

            local rowHeight = 75
            local rowColor =
            {
                default = { 255, 255, 255 },
                over = { 0, 174, 239 },
            }
            local lineColor = { 220, 220, 220 }
            local rowCategoryHeight = 50
            local rowCategoryColor =
            {
                default = { 212, 212, 212, 200},
            }
                
            if thisPersonType ~= evacRecs[idx].persontype then
                thisPersonType = evacRecs[idx].persontype – this would cause an error if set to: thisPersonType ~= evacRecs[idx].persontype
                evacTableView:insertRow
                {
                    isCategory = true,
                    rowHeight = rowCategoryHeight,
                    rowColor = rowCategoryColor,
                    lineColor = lineColor,
                }
                evacTableView:insertRow
                {
                    isCategory = false,
                    rowHeight = rowHeight,
                    rowColor = rowColor,
                    lineColor = lineColor,
                }
            else
                evacTableView:insertRow
                {
                    isCategory = false,
                    rowHeight = rowHeight,
                    rowColor = rowColor,
                    lineColor = lineColor,
                }
            end --if

        end – for
        
        evacdb:close()
        
    end – function