help printing a list from JSON data

Hi all, 

Thanks in advanced for any help you can give. I am trying to create a list application that gets data from a public Google Calendar via JSON. I can successfully decode the data and printing the data works…

It’s getting it to print in the actual list widget that’s giving me a headache. I am using a good chunk of code provided by documentation from the corona site for this. Printing data I hard code into a table works fine…printing data I store into a table via ipairs loop is not working at all… 

Code is below:

Thank! 

--import the table view library local tableView = require("tableView") --import the button events library local ui = require("ui") local json = require "json"  local dataURL = "http://www.google.com/calendar/feeds/csnfcl6h9k9qh769t6rs105pto@group.calendar.google.com/public/full?alt=json" display.setStatusBar( display.HiddenStatusBar )  --initial values local screenOffsetW, screenOffsetH = display.contentWidth -  display.viewableContentWidth, display.contentHeight - display.viewableContentHeight local myList, backBtn, detailScreenText local background = display.newRect(0, 0, display.contentWidth, display.contentHeight) background:setFillColor(77, 77, 77) --setup a destination for the list items local detailScreen = display.newGroup() local detailBg = display.newRect(0,0,display.contentWidth,display.contentHeight-display.screenOriginY) detailBg:setFillColor(255,255,255) detailScreen:insert(detailBg) detailScreenText = display.newText("You tapped item", 0, 0, native.systemFontBold, 24) detailScreenText:setTextColor(0, 0, 0) detailScreen:insert(detailScreenText) detailScreenText.x = math.floor(display.contentWidth/2) detailScreenText.y = math.floor(display.contentHeight/2)      detailScreen.x = display.contentWidth --setup functions to execute on touch of the list view items function listButtonRelease( event )     self = event.target     local id = self.id     print(self.id)          detailScreenText.text = "You tapped item ".. self.id                  transition.to(myList, {time=400, x=display.contentWidth\*-1, transition=easing.outExpo })     transition.to(detailScreen, {time=400, x=0, transition=easing.outExpo })     transition.to(backBtn, {time=400, x=math.floor(backBtn.width/2) + screenOffsetW\*.5 + 6, transition=easing.outExpo })     transition.to(backBtn, {time=400, alpha=1 })          delta, velocity = 0, 0 end function backBtnRelease( event )     print("back button released")     transition.to(myList, {time=400, x=0, transition=easing.outExpo })     transition.to(detailScreen, {time=400, x=display.contentWidth, transition=easing.outExpo })     transition.to(backBtn, {time=400, x=math.floor(backBtn.width/2)+backBtn.width, transition=easing.outExpo })     transition.to(backBtn, {time=400, alpha=0 })     delta, velocity = 0, 0 end -- setup some data local data = {} function newDataListener(event)     if (event.isError) then         print ("Error!")     else          print ( "RESPONSE: " .. event.response )         data = json.decode(event.response)         print("success")         print("Hello: " .. data.version)         print("Hello: " .. data.encoding)         for i,entry in ipairs(data.feed.entry) do                          data[i] = {}             data[i] = entry.title["$t"]                         end             end    end network.request ( dataURL, "GET", newDataListener ) local topBoundary = display.screenOriginY + 40 local bottomBoundary = display.screenOriginY + 0 -- create the list of items myList = tableView.newList{     data=data,      default="listItemBg.png",     over="listItemBg\_over.png",     onRelease=listButtonRelease,     top=topBoundary,     bottom=bottomBoundary,     backgroundColor={ 255, 255, 255 },     callback=function(row)              local t = display.newText(row, 0, 0, native.systemFontBold, 16)             t:setTextColor(0, 0, 0)             t.x = math.floor(t.width/2) + 12             t.y = 46              return t         end } --Setup the nav bar  local navBar = display.newImage("navBar.png", 0, 0, true) navBar.x = display.contentWidth\*.5 navBar.y = math.floor(display.screenOriginY + navBar.height\*0.5) local navHeader = display.newText("My List", 0, 0, native.systemFontBold, 16) navHeader:setTextColor(255, 255, 255) navHeader.x = display.contentWidth\*.5 navHeader.y = navBar.y --Setup the back button backBtn = ui.newButton{      default = "backButton.png",      over = "backButton\_over.png",      onRelease = backBtnRelease } backBtn.x = math.floor(backBtn.width/2) + backBtn.width + screenOffsetW backBtn.y = navBar.y  backBtn.alpha = 0  

Updated with newer/cleaner code. 

See below for a more clear explanation

Edited to clean code again.

and to make my issue more clear: 

What I assume I am doing is writing the data from the loop into the data{} 

This does not appear to be the case - when I move the “mylist” tableview function into the for loop that calls the data, it shows the list in the UI correctly. on the outside, it does not. 

So it looks data is not being saved into data{} so if anyone can point me in the right direct so I can keep mylist outside of the loop and have data saved, that would be great. 

The other issue I am having is that with these Google calendars, some of the tables are called something like: “gd$where” 

How would I call that? When I call data.feed.entry.gd$where.location I get an error because of the ‘$’ 

thanks again for any help!

Hi Marc,

My first question is, what tableView library that you’re using?  It doesn’t look like you’re using the Widgets 2.0 tableView (http://docs.coronalabs.com/api/library/widget/newTableView.html), it looks like you’re using something else.  So it’s hard to help you debug your issue without knowing what you’re using.

I also notice that this code looks wrong:

[lua]

for i,entry in ipairs(data.feed.entry) do

    data[i] = {}     – This line looks wrong

    data[i] = entry.title["$t"] 

end

[/lua]

The reason it looks wrong is that the first line declares data[i] as a table, and then the next line immediately ignores that and assigns data[i] to entry.title["$t"] (which I’m guessing is a string).

In answer to your other question, in Lua, myTable.myKey is shorthand for myTable[“myKey”], but you can only use the shorthand when “myKey” doesn’t have any special characters.  Otherwise you have to use the longhand.  So in your case, you would write data.feed.entry[“gd$where”].location.

Hope this helps.

  • Andrew

Hi Andrew, 

I believe you helped me a couple times before so I appreciate you coming back and helping again. 

I’m using this tutorial/example in this case: http://developer.coronalabs.com/content/list-view-1

So if I paste the “myList” code into the for loop with ipairs, it works fine, outside of the loop, I can’t seem to call anything from the JSON table. Do you have any suggestions how I can make the data globally accessible since I’ll be using the JSON tables in other views as well? 

Maybe create a temp file, and encode the JSON to the temp file? 

Hi Marc,

No problem, happy to help.

Unfortunately I think that’s an old/outdated tutorial.  I doubt you’d be able to navigate to it from within the Corona site, you probably found it by Google?  In either case, I’d suggest not relying on it, and instead trying the Widgets library.

That said, when you say you paste the myList code into the loop with ipairs, can you paste here exactly the code that works?  I could interpret “paste the myList code into the loop with ipairs” in a few ways, so I’d like to see which you mean.

My guess is that you’re not storing the information in your data variable in the way that the tableView requires, and that’s why it’s not working, but when you “paste your myList code into the loop with ipairs”, you’re doing something different (perhaps subtly) that works with tableView.  That’s just a case.  I’m also not familiar with the old tableView library, so I don’t know what kind of data it expects to be constructed with.

The other possibility was a scope issue, where data was declared local in a block and thus not visible outside that block.  But I don’t see that happening in your code.

  • Andrew

That is very old pre-Widget 1.0 code.  I’ll send a message to the team that they need to get these samples updated.  Please look in the folder where your Corona SDK is installed.  There will be a SampleCode folder, an in there you should find the latest version of that which uses the latest Widget 2.0 method of building tableViews (which Andrew linked to the docs for you above).

Hi Rob and Andrew, 

Thanks for the help, I figured this was outdated - I’ll look into the new libraries. In the meantime, I think my problem would still carry over so for now we’ll keep working with what I have. 

Andrew, 

This is what I meant when I said pasting the mylist code: 

(excuse the odd formatting)

--import the table view library local tableView = require("tableView") --import the button events library local ui = require("ui") local json = require "json" local dataURL = "http://www.google.com/calendar/feeds/csnfcl6h9k9qh769t6rs105pto@group.calendar.google.com/public/full?alt=json" display.setStatusBar( display.HiddenStatusBar ) --initial values local screenOffsetW, screenOffsetH = display.contentWidth - display.viewableContentWidth, display.contentHeight - display.viewableContentHeight local myList, backBtn, detailScreenText local background = display.newRect(0, 0, display.contentWidth, display.contentHeight) background:setFillColor(77, 77, 77) --setup a destination for the list items local detailScreen = display.newGroup() local detailBg = display.newRect(0,0,display.contentWidth,display.contentHeight-display.screenOriginY) detailBg:setFillColor(255,255,255) detailScreen:insert(detailBg) detailScreenText = display.newText("You tapped item", 0, 0, native.systemFontBold, 24) detailScreenText:setTextColor(0, 0, 0) detailScreen:insert(detailScreenText) detailScreenText.x = math.floor(display.contentWidth/2) detailScreenText.y = math.floor(display.contentHeight/2) detailScreen.x = display.contentWidth --setup functions to execute on touch of the list view items function listButtonRelease( event ) self = event.target local id = self.id print(self.id) detailScreenText.text = "You tapped item ".. self.id transition.to(myList, {time=400, x=display.contentWidth\*-1, transition=easing.outExpo }) transition.to(detailScreen, {time=400, x=0, transition=easing.outExpo }) transition.to(backBtn, {time=400, x=math.floor(backBtn.width/2) + screenOffsetW\*.5 + 6, transition=easing.outExpo }) transition.to(backBtn, {time=400, alpha=1 }) delta, velocity = 0, 0 end function backBtnRelease( event ) print("back button released") transition.to(myList, {time=400, x=0, transition=easing.outExpo }) transition.to(detailScreen, {time=400, x=display.contentWidth, transition=easing.outExpo }) transition.to(backBtn, {time=400, x=math.floor(backBtn.width/2)+backBtn.width, transition=easing.outExpo }) transition.to(backBtn, {time=400, alpha=0 }) delta, velocity = 0, 0 end -- setup some data local data = {} function newDataListener(event) if (event.isError) then print ("Error!") else print ( "RESPONSE: " .. event.response ) data = json.decode(event.response) print("success") print("Hello: " .. data.version) print("Hello: " .. data.encoding) for i,entry in ipairs(data.feed.entry) do data[i] = {} data[i] = entry.title["$t"] -- create the list of items myList = tableView.newList{ data=data, default="listItemBg.png", over="listItemBg\_over.png", onRelease=listButtonRelease, top=topBoundary, bottom=bottomBoundary, backgroundColor={ 255, 255, 255 }, callback=function(row) local t = display.newText(row, 0, 0, native.systemFontBold, 16) t:setTextColor(0, 0, 0) t.x = math.floor(t.width/2) + 12 t.y = 46 return t end } end end end network.request ( dataURL, "GET", newDataListener ) local topBoundary = display.screenOriginY + 40 local bottomBoundary = display.screenOriginY + 0 --Setup the nav bar local navBar = display.newImage("navBar.png", 0, 0, true) navBar.x = display.contentWidth\*.5 navBar.y = math.floor(display.screenOriginY + navBar.height\*0.5) local navHeader = display.newText("My List", 0, 0, native.systemFontBold, 16) navHeader:setTextColor(255, 255, 255) navHeader.x = display.contentWidth\*.5 navHeader.y = navBar.y --Setup the back button backBtn = ui.newButton{ default = "backButton.png", over = "backButton\_over.png", onRelease = backBtnRelease } backBtn.x = math.floor(backBtn.width/2) + backBtn.width + screenOffsetW backBtn.y = navBar.y backBtn.alpha = 0

Hi Marc,

It’s kind of strange that pasting the code like that works and does what you want it to, since it’s creating a new tableView for every step in the loop.  (10 entries in data.feed.entry would mean 10 tableViews…)

  • Andrew

Andrew, Do you have an suggestions on how to store the data outside of the loop? 

In any case, I’m going to start over using the widget 2.0 library. 

Ah, I wasn’t thinking straight. The reason your first version doesn’t work is because, at the time you create the tableView, data hasn’t been populated yet. The network request will take a bit of time to execute, so you need to create the tableView only after the newDataListener is called. That’s why your second method works – because the tableView is created within the listener. You can continue doing that, just don’t put it inside the loop, which doesn’t make sense logically. You could put it in that function, after the loop.

  • Andrew

Andrew, 

Your help here has been extremely valuable! I hope Coronalabs gives special recognition to developers such as yourself who helps us newbies out. I am familiar with the game side of Corona, and while similar, making the business apps has been challenging in a rewarding way. 

Thanks again for all your help. 

We can call this case closed…Until I run into more trouble… :) 

Moving this to a new thread since it’s a different issue. 

Updated with newer/cleaner code. 

See below for a more clear explanation

Edited to clean code again.

and to make my issue more clear: 

What I assume I am doing is writing the data from the loop into the data{} 

This does not appear to be the case - when I move the “mylist” tableview function into the for loop that calls the data, it shows the list in the UI correctly. on the outside, it does not. 

So it looks data is not being saved into data{} so if anyone can point me in the right direct so I can keep mylist outside of the loop and have data saved, that would be great. 

The other issue I am having is that with these Google calendars, some of the tables are called something like: “gd$where” 

How would I call that? When I call data.feed.entry.gd$where.location I get an error because of the ‘$’ 

thanks again for any help!

Hi Marc,

My first question is, what tableView library that you’re using?  It doesn’t look like you’re using the Widgets 2.0 tableView (http://docs.coronalabs.com/api/library/widget/newTableView.html), it looks like you’re using something else.  So it’s hard to help you debug your issue without knowing what you’re using.

I also notice that this code looks wrong:

[lua]

for i,entry in ipairs(data.feed.entry) do

    data[i] = {}     – This line looks wrong

    data[i] = entry.title["$t"] 

end

[/lua]

The reason it looks wrong is that the first line declares data[i] as a table, and then the next line immediately ignores that and assigns data[i] to entry.title["$t"] (which I’m guessing is a string).

In answer to your other question, in Lua, myTable.myKey is shorthand for myTable[“myKey”], but you can only use the shorthand when “myKey” doesn’t have any special characters.  Otherwise you have to use the longhand.  So in your case, you would write data.feed.entry[“gd$where”].location.

Hope this helps.

  • Andrew

Hi Andrew, 

I believe you helped me a couple times before so I appreciate you coming back and helping again. 

I’m using this tutorial/example in this case: http://developer.coronalabs.com/content/list-view-1

So if I paste the “myList” code into the for loop with ipairs, it works fine, outside of the loop, I can’t seem to call anything from the JSON table. Do you have any suggestions how I can make the data globally accessible since I’ll be using the JSON tables in other views as well? 

Maybe create a temp file, and encode the JSON to the temp file? 

Hi Marc,

No problem, happy to help.

Unfortunately I think that’s an old/outdated tutorial.  I doubt you’d be able to navigate to it from within the Corona site, you probably found it by Google?  In either case, I’d suggest not relying on it, and instead trying the Widgets library.

That said, when you say you paste the myList code into the loop with ipairs, can you paste here exactly the code that works?  I could interpret “paste the myList code into the loop with ipairs” in a few ways, so I’d like to see which you mean.

My guess is that you’re not storing the information in your data variable in the way that the tableView requires, and that’s why it’s not working, but when you “paste your myList code into the loop with ipairs”, you’re doing something different (perhaps subtly) that works with tableView.  That’s just a case.  I’m also not familiar with the old tableView library, so I don’t know what kind of data it expects to be constructed with.

The other possibility was a scope issue, where data was declared local in a block and thus not visible outside that block.  But I don’t see that happening in your code.

  • Andrew