Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

DataGrid View with Sorting and Paging using Dojo EnhancedGrid, JsonRest Store, Entity Framework, SQL Server, ASP.NET MVC Web API

0.00/5 (No votes)
8 Sep 2013 2  
DataGrid View with Sorting and Paging using Dojo EnhancedGrid, JsonRest Store, Entity Framework, SQL Server, ASP.NET MVC Web API

Table of Contents

  1. Introduction
  2. Model
  3. View
  4. Controller
  5. See in action
  6. References

Introduction

Dojo Toolkit is an open source modular JavaScript library (or more specifically JavaScript toolkit) designed to ease the rapid development of cross-platform, JavaScript/Ajax-based applications and web sites and provides some really powerful user interface features (Dojo Toolkit). One of the most powerful Dojo tools is DataGrid (DataGrid demo).

In Dojo DataGrid article, I showed you how to use Dojo DataGrid in an MVC project and there, I said that "we need a full article to talk about sorting and paging". Here you are.

This article walks-through the process of creating an EnhancedGrid supporting Paging and Sorting. For making this kind of grid, we will use Dojo EnhancedGrid, Entity Framework, SQL Server and ASP.NET MVC Web API.

Creating Blog Model

This demo uses an ASP.NET Web API Project.

This project uses Entity Framework Database First approach. But this isn't the point, you could also use Entity Framework Code First or Model First. Here, you could find an introduction to Database First development using Entity Framework. Database First allows you to reverse engineer a model from an existing database. You could use the article until you've got your model, your classes and your database in place, nothing more. We will make our controllers and views. Your Model and Database should be something like this:

Home/Index View

Home/Index View should contain all the codes below:

Dojo Data Grid

You could see a complete article about the code below in here and here or here. This view will define our EnhancedGrid.

@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title</title>
    <link rel="stylesheet" 
    href="http://ajax.googleapis.com/ajax/libs/dojo/1.9.1/dojo/resources/dojo.css" />
    <link rel="stylesheet" 
    href="http://ajax.googleapis.com/ajax/libs/dojo/1.9.1/dijit/themes/claro/claro.css" />
    <link rel="stylesheet" 
    href="http://ajax.googleapis.com/ajax/libs/dojo/1.9.1/dojox/grid/resources/claroGrid.css" />
    <!-- load dojo and provide config via data attribute -->
    <script src="http://ajax.googleapis.com/ajax/libs/dojo/1.9.1/dojo/dojo.js" 
    data-dojo-config="async: true, isDebug: true, parseOnLoad: true">
    </script>
</head>
<body class="claro">
    <div style="width: 700px; margin: 10px; height: 450px; 
    min-height: 450px; border: 1px solid #333333;
        overflow: auto">
        <link rel="stylesheet" 
        href="http://ajax.googleapis.com/ajax/libs/dojo/1.9.1/dojox/
        grid/enhanced/resources/claro/EnhancedGrid.css" />
        <script>
            var dataStoreBlog, gridBlog;
 
            require([
            "dojo/store/JsonRest",
            "dojo/store/Memory",
            "dojo/store/Cache",
            "dojox/grid/EnhancedGrid",
            "dojox/grid/enhanced/plugins/Pagination",
            "dojo/data/ObjectStore",
            "dojo/dom-attr",
            "dojo/domReady!"
            ], function (JsonRest, Memory, Cache, EnhancedGrid, Pagination, ObjectStore, domAttr) {
 
                memoryStoreBlog = new Memory({ idProperty: "Id" });
 
                restStoreBlog = new JsonRest({
                    target: "/Api/Blog/"
                    , idProperty: "Id"
                });
 
                cacheStoreBlog = new Cache(restStoreBlog, memoryStoreBlog)
                dataStoreBlog = new ObjectStore({ objectStore: cacheStoreBlog });
 
                gridBlog = new EnhancedGrid({
                    selectable: true,
                    store: dataStoreBlog,
                    structure: [
                        { name: "Id", field: "Id", width: "50px" },
                        { name: "Title", field: "Title", width: "130px" },
                        { name: "Blogger Name", field: 
                        "BloggerName", width: "180px" }
                        ]
                , rowSelector: '20px'
                , plugins: {
                    pagination: {
                        pageSizes: ["10", "25", "50", "100"],
                        description: true,
                        sizeSwitch: true,
                        pageStepper: true,
                        gotoButton: true,
                        maxPageStep: 5,
                        position: "bottom"
                    }
                }
                }, "gridBlog");
 
                gridBlog.startup();
 
            });
   
        </script>
        <div id="gridBlog" style="height: 350px">
        </div>
    </div>
</body>
</html> 

BlogController

As Dojo sends and receives JSON data to perform CRUD operations on the entities, so we need RESTful service within an ASP.NET MVC. We use API controller to make our RESTful service. Because we need Json as output, we must add the following codes to "App_Start/WebApiConfig.cs" to force API controller to return Json as output:

    var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes
                    .FirstOrDefault(t => t.MediaType == "application/xml");
    config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);   

and because sometimes Json failed to serialize the response in Web API, we must add the following codes:

    GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings
                       .ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;  

See here and here for detail.

Adding BlogController

Our "BlogController.cs" must contain the following codes. Here, you could find complete articles about Web-API and API Controller.

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http;
using DojoEnhancedGrid.Models;
using System.Text.RegularExpressions;
 
namespace DojoEnhancedGrid.Controllers
{
   public class BlogController : ApiController
   {
       private BloggingContext db = new BloggingContext();

       // GET api/Blog
       public IEnumerable<Blog> GetBlogs()
       {
          //check if we have something like "Range: 
          //items=0-19" in "Request.Headers"
          string Range = HttpContext.Current.Request.Headers["Range"] == null ? null:
                         HttpContext.Current.Request.Headers["Range"].ToString();

          if (Range == null)
              return null;

          //getting Range
          int IndexOfDash = Range.IndexOf("-");
          int IndexOfEqual = Range.IndexOf("=");

          Int32 a = Convert.ToInt32(Range.Substring(IndexOfEqual + 1, 
                    IndexOfDash - 1 - IndexOfEqual));
          Int32 b = Convert.ToInt32(Range.Substring(IndexOfDash + 1,
                    Range.Length - 1 - IndexOfDash));

Dojo EnhancedGrid? for paging sends Range: items=0-9 in header. So we use HttpContext.Current.Request.Headers["Range"] for getting the Range, and the code above, set the start of range in a and set the end of range in b.

            //getting sort parameter
            string pattern = @"sort\(([_+-])(.+)\)";
 
            string sentence = Request.RequestUri.Query;
 
            List<string> s = new List<string>();
 
            foreach (Match match in Regex.Matches(sentence, pattern))
                s.Add(match.Value.ToString().Replace("%2c", ","));
 
            string[] sortP = new string[] { "", "" };
 
            if (s.Count > 0)
            {
                sortP = s[0].Split('(', ',', ')');// We use the first sort that found in query
                //sortP[1] sortP[2] .... sortP[n] 
            }

Dojo EnhancedGrid? for sorting send something like ?sort(-Title) in query. The code above will find sort parameter ("-Title") in Request.RequestUri.Query and put it in sortP[1].

if (sortP[1].Length > 0) so we have something like "?sort(-Title)" in query. So in code below sortExpression will contain "Title DESC".

Also as you have noticed, we have blogs.SortBy(sortExpression). We use QueryExtensions class in this article that enables us to use Dynamic Sorting with Linq.

            IQueryable<Blog> blogs = db.Blogs;
 
            Int32 blogsCount = blogs.Count();
 
            if (sortP[1].Length > 0) // if we have something like 
                                        // "?sort(+sortparameter)" in query
            {
                string sortExpression = sortP[1].Replace("+", 
                "").Replace("-", "");
 
                if (sortP[1].Contains('-')) 
                sortExpression = string.Concat(sortExpression, " DESC");
 
                blogs = blogs.SortBy(sortExpression).Skip(a).Take(b - a + 1);
            }
            else
            {
                blogs = blogs.OrderBy(i => i.Id).Skip(a).Take(b - a + 1);
            }

Finally, we need to respond to DojoEnhanced request, the range that our Blog ApiController will return and the amount of all records in Response Header in something like "Content-Range:items 0-9/50000" and the records that were in the range. The following three lines will do these:

            string ContentRange = String.Format("items {0}-{1}/{2}", a, b, blogsCount);
 
            HttpContext.Current.Response.AppendHeader("Content-Range", ContentRange);
 
            return blogs.ToList();
        }
 
        // GET api/Blog/5
        public Blog GetBlog(long id)
        {
            Blog blog = db.Blogs.Find(id);
            if (blog == null)
            {
                throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
            }
 
            return blog;
        }
 
        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }
    }
}  

See in Action

Now it's time to see the result.

References

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here