PDA

View Full Version : JSON with non-identical array elements



prasanna_hr
8 Sep 2011, 2:23 AM
Hi,

I am having a hard time modeling and reading the following JSON output into a store. The first element under 'Values' is a kind of header and is of different type than the other elements. :((

Is there a way to skip the first element/read the first element alone to a different model?

{
"Status":"OK",
"Value":[
{
"Type":"QueryHandle",
"Identity":"c6284858-2b0d-4a04-a781-8f68176458bc",
"TotalResultCount":1227
},
{
"Type":"myapp.Expenses.mydomain.Expenses",
"Identity":"1",
"Properties":{
"Description":"test",
"Paid":true,
"GeneratedKey":null,
"Id":1,
"ExpensesDate":{
"Type":"Date",
"Year":2002,
"Month":9,
"Day":4
},
"TrackingNumber":"000001",
"SubmittedOn":{
"Type":"DateTime",
"Year":2002,
"Month":9,
"Day":4,
"Hour":14,
"Minute":43,
"Second":25
},
"SavedOn":{
"Type":"DateTime",
"Year":2002,
"Month":9,
"Day":4,
"Hour":14,
"Minute":43,
"Second":25
},
"SavedOnUtc":{
"Type":"DateTime",
"Year":2002,
"Month":9,
"Day":4,
"Hour":20,
"Minute":43,
"Second":25
},
"TotalReimbursement":12.00
},
"Relationships":{
"ApproveStatus":{
"Type":"myapp.mydomain.Approvals.ApprovalStatus",
"Identity":"Approved",
"Properties":{
"Name":"Approved"
}
}
}
},
{
"Type":"myapp.Expenses.mydomain.Expenses",
"Identity":"2",
"Properties":{
"Description":"Raj August 2002",
"Paid":true,
"GeneratedKey":null,
"Id":2,
"ExpensesDate":{
"Type":"Date",
"Year":2002,
"Month":9,
"Day":5
},
"TrackingNumber":"000002",
"SubmittedOn":{
"Type":"DateTime",
"Year":2002,
"Month":9,
"Day":5,
"Hour":16,
"Minute":31,
"Second":24
},
"SavedOn":{
"Type":"DateTime",
"Year":2002,
"Month":9,
"Day":5,
"Hour":16,
"Minute":31,
"Second":24
},
"SavedOnUtc":{
"Type":"DateTime",
"Year":2002,
"Month":9,
"Day":5,
"Hour":22,
"Minute":31,
"Second":24
},
"TotalReimbursement":1005.94
},
"Relationships":{
"ApproveStatus":{
"Type":"myapp.mydomain.Approvals.ApprovalStatus",
"Identity":"Approved",
"Properties":{
"Name":"Approved"
}
}
}
},
{
"Type":"myapp.Expenses.mydomain.Expenses",
"Identity":"3",
"Properties":{
"Description":"Group Lunch",
"Paid":true,
"GeneratedKey":null,
"Id":3,
"ExpensesDate":{
"Type":"Date",
"Year":2002,
"Month":9,
"Day":13
},
"TrackingNumber":"000003",
"SubmittedOn":null,
"SavedOn":{
"Type":"DateTime",
"Year":2002,
"Month":9,
"Day":13,
"Hour":15,
"Minute":57,
"Second":1
},
"SavedOnUtc":{
"Type":"DateTime",
"Year":2002,
"Month":9,
"Day":13,
"Hour":21,
"Minute":57,
"Second":1
},
"TotalReimbursement":197.09
},
"Relationships":{
"ApproveStatus":{
"Type":"myapp.mydomain.Approvals.ApprovalStatus",
"Identity":"Open",
"Properties":{
"Name":"Open"
}
}
}
},
{
"Type":"myapp.Expenses.mydomain.Expenses",
"Identity":"4",
"Properties":{
"Description":"Trip to Clarica - Waterloo",
"Paid":true,
"GeneratedKey":null,
"Id":4,
"ExpensesDate":{
"Type":"Date",
"Year":2002,
"Month":9,
"Day":11
},
"TrackingNumber":"000004",
"SubmittedOn":null,
"SavedOn":{
"Type":"DateTime",
"Year":2002,
"Month":9,
"Day":11,
"Hour":14,
"Minute":22,
"Second":13
},
"SavedOnUtc":{
"Type":"DateTime",
"Year":2002,
"Month":9,
"Day":11,
"Hour":20,
"Minute":22,
"Second":13
},
"TotalReimbursement":839.04
},
"Relationships":{
"ApproveStatus":{
"Type":"myapp.mydomain.Approvals.ApprovalStatus",
"Identity":"Open",
"Properties":{
"Name":"Open"
}
}
}
},
{
"Type":"myapp.Expenses.mydomain.Expenses",
"Identity":"5",
"Properties":{
"Description":"CD STOMPER",
"Paid":true,
"GeneratedKey":null,
"Id":5,
"ExpensesDate":{
"Type":"Date",
"Year":2002,
"Month":9,
"Day":11
},
"TrackingNumber":"000005",
"SubmittedOn":null,
"SavedOn":{
"Type":"DateTime",
"Year":2002,
"Month":9,
"Day":11,
"Hour":14,
"Minute":36,
"Second":6
},
"SavedOnUtc":{
"Type":"DateTime",
"Year":2002,
"Month":9,
"Day":11,
"Hour":20,
"Minute":36,
"Second":6
},
"TotalReimbursement":31.74
},
"Relationships":{
"ApproveStatus":{
"Type":"myapp.mydomain.Approvals.ApprovalStatus",
"Identity":"Open",
"Properties":{
"Name":"Open"
}
}
}
}
]
}

Thanks
Prasanna

NickT
8 Sep 2011, 8:35 AM
Did you try building a custom Reader? I would suspect the best way to do this is to create a custom reader and deal with this in the read() or getResponseData() methods

NickT
8 Sep 2011, 8:39 AM
you can add a reader definition to your proxy when you define your store. you could drop in a custom reader and handle the method overrides in that custom reader



{
type: 'ajax',
url : vm.environ.server.routePrefix + '/readaccounts',
reader: new Ext.ux.CustomReader({
type: 'json',
root: 'data',
totalProperty: 'totalRecords'
})
}

prasanna_hr
9 Sep 2011, 3:23 AM
NickT, thanks a lot for your prompt response. I searched for some help on how to write custom reader. Couldn't find much other than

http://www.sencha.com/forum/showthread.php?37329-how-to-write-custom-json-reader
http://www.sencha.com/forum/showthread.php?37367-JsonReader.readRecords&highlight=subclass

Both of which didn't give a good idea on what is a working code.

Would you be able to help with some sample code? Basically i would like to read the first record to a model different than the subsequent records.

Thanks again
Prasanna

NickT
9 Sep 2011, 5:48 AM
It looks like the getResponseData method is the one you want to override. You can do that inline (example 1) or you can create a custom reader (example 2)

Example 1: inline override of the method

reader: { type: 'json',
root: 'Value',
getResponseData: function(response) {
try {
var data = Ext.decode(response.responseText);
}
catch (ex) {
throw 'Ext.data.JsonReader.getResponseData: Unable to parse JSON returned by Server.';
}


if (!data) {
throw 'Ext.data.JsonReader.getResponseData: JSON object not found';
}
if(data && data.data && Ext.isArray(data.data)){
data.data.splice(0,1);
}
return data;
}
}





Example 2: Custom Reader


Ext.namespace('Ext.ux.data');

Ext.ux.data.CustomReader = Ext.extend(Ext.data.JsonReader, {
getResponseData: function(response) {
var data = Ext.ux.data.CustomReader.superclass.getResponseData.call(this, response);
if(data && data.data && Ext.isArray(data.data)){
data.data.splice(0,1);
}
return data;
}
});

NickT
9 Sep 2011, 5:51 AM
if you create a custom reader then, when you define your store's proxy, just instantiate the custom reader right there...


{ type: 'ajax',
url : vm.environ.server.routePrefix + '/readaccounts',
reader: new Ext.ux.data.CustomReader({
type: 'json',
root: 'Value',
totalProperty: 'totalRecords'
})
}

prasanna_hr
9 Sep 2011, 12:12 PM
NickT

I owe you one!! :) It worked!!! Thanks a lot.

I needed to make a small change though ('data.data' had to be replaced by 'data.Value'). Working code is below

proxy: {
type: 'ajax',
url: '../apiwrapper/rwrapper?static=true',
reader: {
type: 'json',
root: 'Value',
getResponseData: function (response) {
try {
var data = Ext.decode(response.responseText);
} catch (ex) {
throw 'Ext.data.JsonReader.getResponseData: Unable to parse JSON returned by Server.';
}
if (!data) {
throw 'Ext.data.JsonReader.getResponseData: JSON object not found';
}
if (data && data.Value && Ext.isArray(data.Value)) {
data.Value.splice(0, 1);
}
return data;
}
}
}

I had to use the inline override because when i used the CustomReader, I got the following error

Uncaught TypeError: Object [object Object] has no method 'getTotal'

Thanks again!
Prasanna

prasanna_hr
9 Sep 2011, 12:15 PM
Now that I got rid of the error record, I would still want to make use of it. Can I load into a model just from this one record (perhaps in the getResponseData function itself?)

Thanks
Prasanna

NickT
9 Sep 2011, 12:45 PM
Yes, you could do something similar to this. Create a model instance and configure with the data in that first array structure you have. You can map the known fields like this, or loop through the model fields and find those values in the array object that you have...


var record = Ext.ModelMgr.create({}, 'specials'); record.set(record.idProperty, Argon.guid());
record.set('isNew', true);
// TODO: if you are an admin, you have to pick a venueID
record.set('venueID', vm.user.currentVenueID);
record.set('venueName', vm.venues.getById(vm.user.currentVenueID).get('venueUnitName'));




then, you can add it to a store that you have created and commit the record...

So, create and register a model,
create a store to house the model records
create a model instance as shown above
map data to the model and add it to store