I really love jqGrid! If you haven’t used it before – try it!
http://www.trirand.com/blog/
To be able to use it with ASP.NET MVC and JSON I created a generic model class to easier reuse it when passing it around in MVC actions in the controller.
To load jqGrid with data (JSON) I call an MVC action like this:
1: $('#StoreGrid').jqGrid({
2: url: '<%=Url.Action("StoreList", "StoreController") %>',
3: datatype: 'json',
4: mtype: 'POST',
5: colNames: ['Store Name', 'Store Address'],
6: colModel: [
7: { name: 'Name', index: 'Name' },
8: { name: 'Address', index: 'Address'},
9: ]
10: ...
Just an example, you get the point. Then in my action I do:
1: public JsonResult StoreList(string sidx, string sord, int page, int rows)
2: {
3: ...
4: // Load data from repository
5: IQueryable<Store> stores = _repository.GetAllStores();
6: int totalRecords = stores.Count();
7: int totalPages = (int)Math.Ceiling(totalRecords/(double)rows);
8:
9: // Convert business model to view model
10: List<StoreListItem> storeListItems =
11: stores
12: .Select(s => new StoreListItem(s.Id, s.Name, s.Address)
13: .ToList();
14:
15: // Create JSON data that jqGrid understands :-)
16: var jsonData = new JqGridJsonModelView<StoreListItem>
17: {
18: total = totalPages,
19: page = page,
20: records = totalRecords,
21: rows = storeListItems
22: };
23: return Json(jsonData, JsonRequestBehavior.AllowGet);
Ignore the repository stuff, paging and sorting is ignored here for simplicity – you shouldn’t – hence the totalPages calculation is redundant (but it wont be if you call e.g. GetStores() and pass paging and sorting parameters to it). Anyway, the key here is the JqGridJsonModelView<T> class. With it I can create any class (in this case StoreListItem) and it will create JSON data that jqGrid understands. Lovely! But what does it do? It’s really simple:
1: /// <summary>
2: /// See http://www.trirand.com/jqgridwiki/doku.php?id=wiki:retrieving_data#json_data
3: /// </summary>
4: public class JqGridJsonModelView<T> where T : IHaveJqGridCells
5: {
6: /// <summary>
7: /// Total number of pages
8: /// </summary>
9: public int total { get; set; }
10:
11: /// <summary>
12: /// Current page
13: /// </summary>
14: public int page { get; set; }
15:
16: /// <summary>
17: /// Total number of records
18: /// </summary>
19: public int records { get; set; }
20:
21: public IList<T> rows { get; set; }
22: }
The property names has a bad naming here, but it must corrolate with jqGrid (
http://www.trirand.com/jqgridwiki/doku.php?id=wiki:retrieving_data#json_data). T here is the model, in this case StoreListItem. But what’s IHaveJqGridCells? Again, simple:
1: public interface IHaveJqGridCells
2: {
3: string id { get; set; }
4:
5: string[] cell { get; }
6: }
Bad naming, as said before, but it’s what jqGrid uses. So, all we have to do is let StoreListItem implement IHaveJqGridCells:
1: public class StoreListItem : IHaveJqGridCells
2: {
3: // Implement interface
4: public string id { get; set; }
5:
6: // Private properties to "disable" serialization (no need to be public anyway)
7: readonly string Name;
8: readonly string Address;
9:
10: public StoreListItem(int id, string name, string address)
11: {
12: this.id = id.ToString();
13:
14: Name = name;
15: Address = address;
16: }
17:
18: // Implement interface
19: public string[] cell
20: {
21: get
22: {
23: return new[] { Name, Address }
24: }
25: }
26:
Voila! We’re done! Now this class will be serialized into JSON (by MVC action). The serialized result will look like this:
1: {
2: "total" : "xxx",
3: "page" : "yyy",
4: "records" : "zzz",
5: "rows" : [
6: {"id" : "1", "cell" : ["Store 1", "Address 1"]},
7: {"id" : "2", "cell" : ["Store 2", "Address 2"]},
8: ...
9: ]
10: }
Now it’s really easy to extend the model and/or reuse it.
Hope you like it!
Update (requested by danlimerick):
If you want to do sorting/paging. I usually use
Dynamic Linq Query Library and make sure the naming in the jqGrid colModel corrolates to the naming in the repository:
1: IQueryable<Store> stores = _repository.GetStores(sidx, sord, (page - 1), rows);
2:
3: ...
4:
5: public IQueryable<Store> GetStores(string sortIndex, string sortOrder, int page, int rowsPerPage)
6: {
7: return _context.Store
8: .OrderBy(sortIndex + " " + sortOrder)
9: .Skip(page * rowsPerPage)
10: .Take(rowsPerPage);
11: }
I wouldn’t call it elegant, but it’s a pretty convenient way.