Ext JS JsonStore and Linq to JSON Gotcha
Here's a little gotcha that had be scratching my head for a moment. I was testing the Grid component of the excellent Ext JS framework when I ran into a problem loading the JSON result into the grid.
It seemed simple enough - populate the grid from JSON data returned by a controller action method. When I ran the code the grid wasn't populated: the Ext JSONReader was throwing an error "root is undefined". I checked and double checked everything but could not see what the problem was.
Here's the JavaScript to create the JsonStore for the grid:
var ds = new Ext.data.JsonStore({ url: '/Home/GetData', totalProperty: 'totalRecords', root: 'requests', id: "ReqNo", fields: ['Division', 'Department'], listeners: { loadexception: function(proxy, store, response, e) { alert(e.message); } } });
Here's the controller method that returns the JSON:
public JsonResult GetData(int? start, int? limit) { limit = limit ?? 25; start = start ?? 0; string dataPath = HttpContext.Server.MapPath("~/Data/TestData.xml"); XDocument xDoc = XDocument.Load(dataPath); var results = from requests in xDoc.Descendants("requests") select new { totalRecords = requests.Elements("request").Count(), requests = (from request in requests.Elements("request") select new NBWeb.Models.Request { Division = request.Element("Division").Value, Department = request.Element("Department").Value }).Skip((int)start).Take((int)limit) }; return this.Json(results); }
And here's an example of the JSON it emits:
[{
"totalRecords":200,
"requests":[
{"Division":"Division 1","Department":"Department 5",},
{"Division":"Division 2","Department":"Department 4",},
{"Division":"Division 3","Department":"Department 5",},
{"Division":"Division 4","Department":"Department 6",},
]
}]
Eventually, upon examining the JSON for the tenth time, it dawned on me - the entire JSON data was nested in a redundant outer array. So the JsonStore root property was not being found - it was looking for:
obj["requests"]
but would need to look for:
obj[0]["requests"]
So it was the controller returning slightly malformed JSON. It's a bug in my code - I need to return the inner result of the Linq select rather than the entire result. So I need to take the FirstOrDefault record from the results, like so:
public JsonResult GetData(int? start, int? limit) { limit = limit ?? 25; start = start ?? 0; string dataPath = HttpContext.Server.MapPath("~/Data/TestRequests2500.xml"); XDocument xDoc = XDocument.Load(dataPath); var results = (from requests in xDoc.Descendants("requests") select new { totalRecords = requests.Elements("request").Count(), requests = (from request in requests.Elements("request") select new NBWeb.Models.Request { Division = request.Element("Division").Value, Department = request.Element("Department").Value, }).Skip((int)start).Take((int)limit) }).FirstOrDefault(); return this.Json(results); }
And here's the corrected JSON it emits (note the absence of the outer square brackets):
{
"totalRecords":200,
"requests":[
{"Division":"Division 1","Department":"Department 5",},
{"Division":"Division 2","Department":"Department 4",},
{"Division":"Division 3","Department":"Department 5",},
{"Division":"Division 4","Department":"Department 6",},
]
}
Seems like a dumb mistake to make but it took a bit of debugging to find it - hopefully this post will save someone out there some time.
Published: Friday, 24 October 2008 05:22 PM by Steve
Comments: 0 Comments