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: 5 Comments