Is there an example of using a TableView with a Network.Request to get the data asyncronously?

Hi I am trying to figure out how I can make the table wait to load the data until the network request has completed and decoded the json data. Is there an example of such a beast somewhere? [import]uid: 125860 topic_id: 33572 reply_id: 333572[/import]

The way I ended up doing it was to force the table to re-render itself after network.request() finishes and calls its onComplete handler. In that handler after you are done populating the tableRow. It’s kind of tricky keeping track of which tableView row you need to update. A lot depends on when and where you are calling networkRequest from.

Here is a little code snippet for forcing a tableView to re-render itself:

local function updateTable()  
 local y = myList:getContentPosition()  
 myList:scrollToY(y,0)  
end   
  
local function reRender()  
 for i=1,#myList.content.rows do  
 myList.content.rows[i].reRender = true  
 end  
 updateTable()  
end  

[import]uid: 199310 topic_id: 33572 reply_id: 133426[/import]

The way I ended up doing it was to force the table to re-render itself after network.request() finishes and calls its onComplete handler. In that handler after you are done populating the tableRow. It’s kind of tricky keeping track of which tableView row you need to update. A lot depends on when and where you are calling networkRequest from.

Here is a little code snippet for forcing a tableView to re-render itself:

local function updateTable()  
 local y = myList:getContentPosition()  
 myList:scrollToY(y,0)  
end   
  
local function reRender()  
 for i=1,#myList.content.rows do  
 myList.content.rows[i].reRender = true  
 end  
 updateTable()  
end  

[import]uid: 199310 topic_id: 33572 reply_id: 133426[/import]

Hi Rob,

Can you post a more complete example with list creation and the network request?
I’m having some dificulty positioning your code snippet.

Thanks [import]uid: 158485 topic_id: 33572 reply_id: 133914[/import]

Hi @facada.

I’m afraid I can’t because there are too many variables. What are you downloading? What content needs to go into the table row? What content do you have there to begin with? What just needs updated? Where are you downloading it from? What causes network.request() to be called?

It’s way too much to make into a forum type post. [import]uid: 199310 topic_id: 33572 reply_id: 133930[/import]

When asynchronous and lazy loading occurs correctly on screen, it all seems so smooth and simple. But there’s a lot that needs to go on behind the scenes to make it happen. On the plus side, Corona has all the right calls and hooks you’ll need to make lists load fast and scroll fast no matter how big they are (provided you approach managing your particular data well). Here’s one devs solution:

http://developer.coronalabs.com/forum/2012/01/11/asynchronous-image-loading-help-needed

I’m especially impressed with Coronas strategy to automatically render (load) rows when they come into view on screen, and automatically de-render (free) them when they scroll off screen. While there’s a tiny performance penalty as you scroll (not really noticeable), there’s an incredible advantage to the “lazy loading” that it provides. Lists with thousands of graphics (which would never all load at once) load flawlessly, and scroll very fast… If you’re using thumbnail sized images, they’re loaded and onscreen before you even notice… It’s pure genius, and if you follow their lead, pretty darn easy (for something so powerful).

Best of luck.

Note: to see how the lazy loading works, put a print statement showing the current row in your onRender function (and scroll up and down the list, sending items on/off the display)… Only the rows visible will be called to load up/render… When they go off screen, they are released (and reloaded if they are scrolled back on – all automatically). [import]uid: 79933 topic_id: 33572 reply_id: 133931[/import]

Hi,

This is driving me nuts!! There must be a simple solution for this, but I think I’m too newbie for get it…
I have the tableview and the request for the JSON object. The problem is that the tableview is rendered before the network request is finished generating the “attempt to index field ‘?’ (a nil value)”

Please, analyse my code, and save my day :wink:

Thanks

[lua]local storyboard = require “storyboard”
local listScene = storyboard.newScene()

local data = {}
local json = require(“json”)
local URL = “https://example.com/json

– network request json data
local function jsonGet(event)
if ( event.isError ) then
print ( “Network error - download failed” )
else
data = json.decode(event.response)
end
end
network.request( URL, “GET”, jsonGet )

– tableView scene
function listScene:createScene( event )
local group = self.view

local list = widget.newTableView{
data=data,
top = top+44,
height = 322,
maskFile = “assets/mask-320x322.png”
}

–Handle row rendering
local function onRowRender( event )
local row = event.row
local rowGroup = event.view

–local lbl_title = “Photo Title”
local lbl_title = data[event.row].photo_title

– title
row.title = display.newRetinaText( rowGroup, lbl_title … row.index, 0, 0, native.systemFontBold, 14 )
row.title:setTextColor( 0,0,0, 255 )
row.title:setReferencePoint( display.TopLeftReferencePoint )
row.title.x, row.title.y = 80, 5
rowGroup:insert( row.title )
end

– handles row presses/swipes
local function rowListener( event )
local row = event.row
local background = event.background

if event.phase == “release” or event.phase == “tap” then
background:setFillColor( 0, 110, 233, 255 )
row.reRender = true
– set chosen row index to this row’s index
chosenRowIndex = row.index
– go to row scene
storyboard.gotoScene( “listrowScene”, “slideLeft”, 350 )
end
end

– insert rows into list (tableView widget)
for i=1,1 do
local isCategory
local rowColor
local rowHeight = 80
local listener = rowListener
list:insertRow{
height = rowHeight,
rowColor = rowColor,
isCategory = isCategory,
onRender = onRowRender,
listener = listener
}
end

group:insert( list )
end
listScene:addEventListener( “createScene”, listScene )

return listScene[/lua] [import]uid: 189638 topic_id: 33572 reply_id: 134043[/import]

Hi Rob,

Can you post a more complete example with list creation and the network request?
I’m having some dificulty positioning your code snippet.

Thanks [import]uid: 158485 topic_id: 33572 reply_id: 133914[/import]

Hi @facada.

I’m afraid I can’t because there are too many variables. What are you downloading? What content needs to go into the table row? What content do you have there to begin with? What just needs updated? Where are you downloading it from? What causes network.request() to be called?

It’s way too much to make into a forum type post. [import]uid: 199310 topic_id: 33572 reply_id: 133930[/import]

I think you are mixing the old tableView with the newer widget.tableView in how to do things.

The newer widget.tableView does not take a data parameter. See:
http://docs.coronalabs.com/api/library/widget/newTableView.html
But that’s being ignored, lets look at how network.request() works. It fires off and runs in the background retrieving your data. When it’s done it fires off a call back. In your code your tableView constructor and inserts run immediately after requesting the data but before it loads. data is nil at that point and your onRender functions will not work because of all the nil pointers.

You want to do those list:insertRows() inside your call back from network.request()
[import]uid: 199310 topic_id: 33572 reply_id: 134160[/import]

When asynchronous and lazy loading occurs correctly on screen, it all seems so smooth and simple. But there’s a lot that needs to go on behind the scenes to make it happen. On the plus side, Corona has all the right calls and hooks you’ll need to make lists load fast and scroll fast no matter how big they are (provided you approach managing your particular data well). Here’s one devs solution:

http://developer.coronalabs.com/forum/2012/01/11/asynchronous-image-loading-help-needed

I’m especially impressed with Coronas strategy to automatically render (load) rows when they come into view on screen, and automatically de-render (free) them when they scroll off screen. While there’s a tiny performance penalty as you scroll (not really noticeable), there’s an incredible advantage to the “lazy loading” that it provides. Lists with thousands of graphics (which would never all load at once) load flawlessly, and scroll very fast… If you’re using thumbnail sized images, they’re loaded and onscreen before you even notice… It’s pure genius, and if you follow their lead, pretty darn easy (for something so powerful).

Best of luck.

Note: to see how the lazy loading works, put a print statement showing the current row in your onRender function (and scroll up and down the list, sending items on/off the display)… Only the rows visible will be called to load up/render… When they go off screen, they are released (and reloaded if they are scrolled back on – all automatically). [import]uid: 79933 topic_id: 33572 reply_id: 133931[/import]

Hi,

This is driving me nuts!! There must be a simple solution for this, but I think I’m too newbie for get it…
I have the tableview and the request for the JSON object. The problem is that the tableview is rendered before the network request is finished generating the “attempt to index field ‘?’ (a nil value)”

Please, analyse my code, and save my day :wink:

Thanks

[lua]local storyboard = require “storyboard”
local listScene = storyboard.newScene()

local data = {}
local json = require(“json”)
local URL = “https://example.com/json

– network request json data
local function jsonGet(event)
if ( event.isError ) then
print ( “Network error - download failed” )
else
data = json.decode(event.response)
end
end
network.request( URL, “GET”, jsonGet )

– tableView scene
function listScene:createScene( event )
local group = self.view

local list = widget.newTableView{
data=data,
top = top+44,
height = 322,
maskFile = “assets/mask-320x322.png”
}

–Handle row rendering
local function onRowRender( event )
local row = event.row
local rowGroup = event.view

–local lbl_title = “Photo Title”
local lbl_title = data[event.row].photo_title

– title
row.title = display.newRetinaText( rowGroup, lbl_title … row.index, 0, 0, native.systemFontBold, 14 )
row.title:setTextColor( 0,0,0, 255 )
row.title:setReferencePoint( display.TopLeftReferencePoint )
row.title.x, row.title.y = 80, 5
rowGroup:insert( row.title )
end

– handles row presses/swipes
local function rowListener( event )
local row = event.row
local background = event.background

if event.phase == “release” or event.phase == “tap” then
background:setFillColor( 0, 110, 233, 255 )
row.reRender = true
– set chosen row index to this row’s index
chosenRowIndex = row.index
– go to row scene
storyboard.gotoScene( “listrowScene”, “slideLeft”, 350 )
end
end

– insert rows into list (tableView widget)
for i=1,1 do
local isCategory
local rowColor
local rowHeight = 80
local listener = rowListener
list:insertRow{
height = rowHeight,
rowColor = rowColor,
isCategory = isCategory,
onRender = onRowRender,
listener = listener
}
end

group:insert( list )
end
listScene:addEventListener( “createScene”, listScene )

return listScene[/lua] [import]uid: 189638 topic_id: 33572 reply_id: 134043[/import]

Cheesy example but it works, thanks for everyone’s help.

[code]
display.setStatusBar(display.HiddenStatusBar)

local widget = require “widget”
local json = require(“json”)
local data = {}
local w,h = display.contentWidth, display.contentHeight
local listOptions = { top = 0-40, height = 410, width = 320, maskFile = “mask-410.png”, bgColor = { 0, 0, 0, 0 } }
local URL = “http://www.mikelovesandy.com/getgames.php
local list

local function jsonGet(event)
if ( event.isError ) then
print ( “Network error - download failed” )
else
data = json.decode(event.response)
loadTableView()
end
end

function loadTableView()
list = widget.newTableView( listOptions )
for i=1,#data do
list:insertRow{
onRender=onRowRender
}
end
end

function onRowRender( event )
local row = event.target
local rowGroup = event.view
local text = display.newRetinaText( data[event.index].Name, 12, 0, “Verdana”, 18 )
text:setReferencePoint( display.CenterLeftReferencePoint )
text.y = row.height * 0.5
if not row.isCategory then
text.x = 15
text:setTextColor( 0 )
end
rowGroup:insert( text )
end

network.request( URL, “GET”, jsonGet )
[/code] [import]uid: 125860 topic_id: 33572 reply_id: 134348[/import]

I think you are mixing the old tableView with the newer widget.tableView in how to do things.

The newer widget.tableView does not take a data parameter. See:
http://docs.coronalabs.com/api/library/widget/newTableView.html
But that’s being ignored, lets look at how network.request() works. It fires off and runs in the background retrieving your data. When it’s done it fires off a call back. In your code your tableView constructor and inserts run immediately after requesting the data but before it loads. data is nil at that point and your onRender functions will not work because of all the nil pointers.

You want to do those list:insertRows() inside your call back from network.request()
[import]uid: 199310 topic_id: 33572 reply_id: 134160[/import]

Cheesy example but it works, thanks for everyone’s help.

[code]
display.setStatusBar(display.HiddenStatusBar)

local widget = require “widget”
local json = require(“json”)
local data = {}
local w,h = display.contentWidth, display.contentHeight
local listOptions = { top = 0-40, height = 410, width = 320, maskFile = “mask-410.png”, bgColor = { 0, 0, 0, 0 } }
local URL = “http://www.mikelovesandy.com/getgames.php
local list

local function jsonGet(event)
if ( event.isError ) then
print ( “Network error - download failed” )
else
data = json.decode(event.response)
loadTableView()
end
end

function loadTableView()
list = widget.newTableView( listOptions )
for i=1,#data do
list:insertRow{
onRender=onRowRender
}
end
end

function onRowRender( event )
local row = event.target
local rowGroup = event.view
local text = display.newRetinaText( data[event.index].Name, 12, 0, “Verdana”, 18 )
text:setReferencePoint( display.CenterLeftReferencePoint )
text.y = row.height * 0.5
if not row.isCategory then
text.x = 15
text:setTextColor( 0 )
end
rowGroup:insert( text )
end

network.request( URL, “GET”, jsonGet )
[/code] [import]uid: 125860 topic_id: 33572 reply_id: 134348[/import]

this example doesn`t work((

@aglichev_n:

The code from @mmahon512 looks like widget-v1 code and will not work with widget 2.0

so, i decide it

display.setStatusBar(display.HiddenStatusBar) local widget = require "widget" local json = require("json") local data = {} local w,h = display.contentWidth, display.contentHeight local URL = "http://nik.gm4x4.ru/script.php" local list local function jsonGet(event) data = json.decode(event.response) loadTableView() end function loadTableView() list = widget.newTableView { top = 0, height = 1280, width = 720, noLines=true, friction = 0.5, maskFile = "mask.png", onRowRender = onRr } for i=1,#data.name do list:insertRow{ rowHeight=150, rowColor = { default = { 255, 255, 255 }, over = { 0, 0, 0 } } } end end function onRr( event ) local row = event.row local ind = event.row.index local textPrice = display.newText(row, data.price[ind], 0, 0, 720, 43, native.systemFont, 42 ) textPrice:setTextColor(0,0,0) end network.request( URL, "GET", jsonGet ) 

Русские, я выжил xDD

this example doesn`t work((

@aglichev_n:

The code from @mmahon512 looks like widget-v1 code and will not work with widget 2.0