PDA

View Full Version : Nested JSON data and JsonStore mapping question



xsikal
8 Feb 2010, 3:06 PM
Hi all....

I have a JSON string that represents multiple nested objects, (which may or may not have values), as shown below. The JSON parses out (via JSLint) as being good, but I get errors in IE (not in Firefox, even with Firebug... though the code does not function, regardless), when mapping the fields. I'm very new to Ext, (and JSON), so it's quite possible I'm doing something dumb. I'd greatly appreciate any assistance.

My data is structured as:
<category>
----<reg options>
----<benefits>
----<benefit options>
----<attributes>

Here's the JSON string I ended up using:



[{ "categoryname": "Marathon Registrations", "regoptions":{ "rname":"Individual Ticket","ragedescription":"(Must be between the age of 5 and 30)","rdescription":"Individual Ticket","rmingoaltext":"some text","rfeetext":"Fee: 25","rearlybirdtext":"","rlatefeetext":"","positionstext":"48","benefits":[{"options":[{"attributes":[]}]}]}},{ "categoryname": "Survivor Registrations", "regoptions":{ "rname":"Group","ragedescription":"(Must be between the age of 18 and 50)","rdescription":"Group","rmingoaltext":"some text","rfeetext":"Fee: 20","rearlybirdtext":"","rlatefeetext":"","positionstext":"9999","benefits":[{"options":[{"attributes":[]}]}]}},{ "categoryname": "Team Registrations", "regoptions":{ "rname":"Corporate Sponsor","ragedescription":"(Must be between the age of 25 and 70)","rdescription":"Corporate Sponsor","rmingoaltext":"some text","rfeetext":"Fee: 2500","rearlybirdtext":"","rlatefeetext":"","positionstext":"9999","benefits": [{"benefitid":"d0d7988f-d9a0-42f9-b29d-b1c01bff1100","benefitname":"Event T-Shirt","options":[{"benefitoptionid":"72e5da37-7ef1-4bbf-aab5-db6306f9ef25","benefitoptionname":"Size","attributes":[{"attributeid":"3a722a90-6ca6-4444-92d2-3e3cce487b1d","attributename":"Large"},{"attributeid":"ea781b91-595d-42c4-8fce-dbcaa42a00f1","attributename":"Medium"},{"attributeid":"ca6911c0-e3a1-4d79-aebe-2708d9336969","attributename":"Small"}]}]}]}}]
And here is the mapping I am doing:



TEST.netcommunity.regOptions.store = new Ext.data.JsonStore({
fields: [
{ name: 'categoryname' },
{ name: 'regoptions', mapping: 'regoptions' },
{ name: 'rid', mapping: 'regoptions.rid' },
{ name: 'rname', mapping: 'regoptions.rname' },
{ name: 'ragerestriction', mapping: 'regoptions.ragerestriction' },
{ name: 'rdescription', mapping: 'regoptions.rdescription' },
{ name: 'rmingoaltext', mapping: 'regoptions.rmingoaltext' },
{ name: 'rfeetext', mapping: 'regoptions.rfeetext' },
{ name: 'rearlybirdtext', mapping: 'regoptions.rearlybirdtext' },
{ name: 'rlatefeetext', mapping: 'regoptions.rlatefeetext' },
{ name: 'positionstext', mapping: 'regoptions.positionstext' },
{ name: 'benefits', mapping: 'regoptions.benefits' },
{ name: 'benefitid', mapping: 'regoptions.benefits.benefitid' },
{ name: 'benefitname', mapping: 'regoptions.benefits.benefitname'},
{ name: 'options', mapping: 'regoptions.benefits.options'},
//{ name: 'benefitoptionid', mapping: 'regoptions.benefits.options.benefitoptionid'},
//{ name: 'benefitoptionname', mapping: 'regoptions.benefits.options.benefitoptionname'},
{ name: 'attributes', mapping: 'regoptions.benefits.options.attributes'},
{ name: 'attributeid', mapping: 'regoptions.benefits.options.attributes.attributeid'},
{ name: 'attributename', mapping: 'regoptions.benefits.options.attributes.attributename'}
],
data: myData
});
...where myData is the JSON string posted previously.

Finally, here is my very rudimentary DataView/XTemplate, although I don't believe it's actually getting that far at runtime:



TEST.netcommunity.regOptions.view = new Ext.DataView({
style: 'overflow:auto',
autoHeight: true,
width: 700,
store: TEST.netcommunity.regOptions.store,
tpl: new Ext.XTemplate(
'<tpl for=".">',
'<ul>Category Name: {categoryname}</u>',
'<tpl for="regoptions"><br>',
'<input type="radio" name="regoption" />{rname}{ragerestriction}',
'<br>reg option text: {rtext}',
'<tpl for="benefits">',
'<br>benefit name: {benefitname}',
'<tpl for="options">',
'<br>{benefitoptionname}:<br>',
'<tpl for="attributes">',
'<br>{attributeid}: {attributename}',
'</tpl>',
'</tpl>',
'</tpl>',
'</tpl>',
'</ul></tpl>'
)
});
When loading the page, I was initially getting the JS error :
'regoptions.benefits.options.benefitoptionid' is null or not an object

For test purposes, I commented out that and other lines, (as seen above), and now get:

'regoptions.benefits.options.attributes' is null or not an object

Any ideas? I assume I'm doing something wrong, either in my mapping or my JSON creation, (particularly for the 'empty' elements), but could use a nudge in the proper direction.

Thanks in advance!

xsikal
9 Feb 2010, 1:43 AM
I wanted to update this with what I've tried since my original post, in the hopes that someone can confirm my findings, and suggest a solution.

I reduced my Json string to a single root-level object, (with the same multiple nestings as before). I chose the object that had data at every level, to make sure that the issue was not a result of trying to map to an empty node.

When I ran the page again with the revised Json string, I got the same error, with the properties at the "options" level (i.e.regoptions.benefits.options.XXXX) always being seen as null. This seems to point to, not an error in my mapping, but an inability for the JsonStore to map to more than ~2 levels of nesting.

Does that match anyone else's expectations? (And, if so, how would you suggest handling a data structure like this one?)

My lighter Json string:

[{ "categoryname": "Team Registrations", "regoptions":{ "rname":"Corporate Sponsor","ragedescription":"(Must be between the age of 25 and 70)","rdescription":"Corporate Sponsor","rmingoaltext":"some text","rfeetext":"Fee: 2500","rearlybirdtext":"","rlatefeetext":"","positionstext":"9999","benefits": [{"benefitid":"d0d7988f-d9a0-42f9-b29d-b1c01bff1100","benefitname":"Event T-Shirt","options":[{"benefitoptionid":"72e5da37-7ef1-4bbf-aab5-db6306f9ef25","benefitoptionname":"Size","attributes":[{"attributeid":"3a722a90-6ca6-4444-92d2-3e3cce487b1d","attributename":"Large"},{"attributeid":"ea781b91-595d-42c4-8fce-dbcaa42a00f1","attributename":"Medium"},{"attributeid":"ca6911c0-e3a1-4d79-aebe-2708d9336969","attributename":"Small"}]}]}]}}]Unchanged JsonStore mapping:


TEST.netcommunity.regOptions.store = new Ext.data.JsonStore({
fields: [
{ name: 'categoryname' },
{ name: 'regoptions', mapping: 'regoptions' },
{ name: 'rid', mapping: 'regoptions.rid' },
{ name: 'rname', mapping: 'regoptions.rname' },
{ name: 'ragerestriction', mapping: 'regoptions.ragerestriction' },
{ name: 'rdescription', mapping: 'regoptions.rdescription' },
{ name: 'rmingoaltext', mapping: 'regoptions.rmingoaltext' },
{ name: 'rfeetext', mapping: 'regoptions.rfeetext' },
{ name: 'rearlybirdtext', mapping: 'regoptions.rearlybirdtext' },
{ name: 'rlatefeetext', mapping: 'regoptions.rlatefeetext' },
{ name: 'positionstext', mapping: 'regoptions.positionstext' },
{ name: 'benefits', mapping: 'regoptions.benefits' },
{ name: 'benefitid', mapping: 'regoptions.benefits.benefitid' },
{ name: 'benefitname', mapping: 'regoptions.benefits.benefitname'},
{ name: 'options', mapping: 'regoptions.benefits.options'},
//{ name: 'benefitoptionid', mapping: 'regoptions.benefits.options.benefitoptionid'},
//{ name: 'benefitoptionname', mapping: 'regoptions.benefits.options.benefitoptionname'},
{ name: 'attributes', mapping: 'regoptions.benefits.options.attributes'},
{ name: 'attributeid', mapping: 'regoptions.benefits.options.attributes.attributeid'},
{ name: 'attributename', mapping: 'regoptions.benefits.options.attributes.attributename'}
],
data: myData
});


Thank you in advance!

cavalleydude
18 May 2010, 1:19 PM
I have this same issue. Does anyone know how to handle nested arrays of data? I searched everywhere and cannot find out how to handle this type of JSON data source.

Any help would be greatly appreciated.

steffenk
18 May 2010, 2:17 PM
Hi,

it's no problem to use nested json in the store, and the code is correct. But a JsonStore is different to an ArrayStore:
You need a root property, and a totalProperty.

I nested the given json with that, and here is a grid showing some of these fields in a grid. Look at source code to see how it's done.

http://dev.sk-typo3.de/ext/nestedjson.html

cavalleydude
18 May 2010, 2:32 PM
Thanks Steffen! Okay, I understand now, thanks for fast response. I figured this must be doable, but could not find a clear example.

qlegrand
19 May 2010, 6:18 PM
Hi,

it's no problem to use nested json in the store, and the code is correct. But a JsonStore is different to an ArrayStore:
You need a root property, and a totalProperty.

I nested the given json with that, and here is a grid showing some of these fields in a grid. Look at source code to see how it's done.

http://dev.sk-typo3.de/ext/nestedjson.html

Hi steffenk,

I have just read this thread with interest but the example shown does not quite address my problem. My JSON data looks like this: >>>>

{"nrrecs":3,"data":[{"sysname":"Default","startTime_min":"2008-01-01 00:00:19","startTime_max":"2008-04-01 00:00:00","eventTypes":[["0","AdapterRxTxn"],["1","TCTxTxn"],["2","MBRxTxn"],["3","MBTxTxnConfirmation"]]},{"sysname":"Backup 1","startTime_min":"2008-01-04 00:00:19","startTime_max":"2008-07-01 00:00:00","eventTypes":[["0","AdapterRxTxn"],["1","TCTxTxn"],["2","MBRxTxn"],["3","MBTxTxnConfirmation"]]},{"sysname":"Backup 2","startTime_min":"2008-01-07 00:00:19","startTime_max":"2008-10-01 00:00:00","eventTypes":[["0","AdapterRxTxn"],["1","TCTxTxn"],["2","MBRxTxn"],["3","MBTxTxnConfirmation"]]}]}
<<<<<

(where the root is "data" and the total property is "nrrecs")

As you can see, each of the 3 response records has two simple fields ("startTime_min" and "startTime_max") and an array "eventTypes" of 4 (could vary between records) elements each consisting of an array of 2 fields (it could be more but 2 will do for now).

My questions are

1) is it possible to configure a JsonStore and associated reader in ExtJs 3.2 which will handle this?
2) if so, what are the appropriate mappings

If it can't be done I'll just have to break the XHR transaction into two requests which seems a shame and really should not be necessary.

PS I'm not using the data store for a grid but to dynamically configure some form elements.

Many thanks for you help so far,

qlegrand.

cavalleydude
19 May 2010, 9:23 PM
I have other more complex JSON strings similar to yours which I also do not know how to format a Store object for.

I have a suggestion for the ExtJS team... How about a tool that generates the JsonReader for a Store object given a JSON object or string? I've seen lots of questions on how to format a Store object given some JSON response. It would be nice to have a tool that could lexicon parse any JSON string into a JsonReader for a Store object.

steffenk
20 May 2010, 3:23 AM
In general json reader is simple: it parse the given json string into an object. The store mapping is simple, it defines shortcuts to the parsed json object.
So for the simple ones mapping is sufficient. If extended logic is needed, or more nested data to extract, there is the convert function which gives you the full record as parameter. You can put own logic in and return the value you need.
http://www.extjs.com/deploy/dev/docs/?class=Ext.data.Field&member=convert

cavalleydude
18 Jun 2010, 7:30 AM
Hi Steffen, thanks for the information, but I'm still a confused ;), Here is my data structure and I'm trying to prototype the record format for the JSON reader. The data I'm really after is the ARRAY of 'care-units', I cannot figure out how to do this. Any help would be awesome.

var data =
{"units":{"care-units":[
{"code":"8-SW","description":"8-SW"},
{"code":"GLB2","description":"GI-310"},
{"code":"ED","description":"External Dept."},
{"code":"7-NE","description":"7-NE"}
],"totalcount":4}}
;


reader: new Ext.data.JsonReader({
root: 'hospital-units',
totalProperty: 'totalcount',
id: 'hospital-units'
},
{name:'hospital-units', mapping: 'hospital-unit'},
{name:'unit', mapping: 'hospital-unit'},
[
{name: 'code', mapping: 'unit.code'},
{name: 'description', mapping: 'unit.description'}
]
),


Thanks,
Scott
cavalleydude