lbrt.Net

Pinoy Software Engineer

ASP.NET MVC, C#: Custom jqGrid object based column definitions

There are not much reference that I’ve seen with regards to customizing a jqGrid based on an object. This sample will allow users to create a customize jqGrid where the grid and column definitions are defined within the c# codebehind. The sample would require download of jqGrid version 4.1.2 and jquery-ui which is required for jqGrid 3.5 and above.

First step is to create a ASP.NET MVC Project – Let’s name it as StepByStepJQGridGuid

Then add the jqGrid and jquery-ui objects to your solution as shown below. jquery-ui objects are marked as blue.

Now we shall add references to this scripts in our page. As a standard, we would be adding the scripts references within the Site.Master, hence allowing the jqGrid scripts to be used by any page inheriting from the Site.Master. add the references within the header tag of the Site.Master page as shown below

<head runat="server">
    <title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
    <link href="../../Content/Site.css" rel="stylesheet" type="text/css" />
    <%-- Add Code --%>
    <link href="../../Scripts/css/ui.jqgrid.css" rel="stylesheet" type="text/css" />
    <link href="../../Scripts/css/ui.multiselect.css" rel="stylesheet" type="text/css" />
    <link href="../../Scripts/css/jquery-ui-1.8.7.css" rel="stylesheet" type="text/css" />
    <script src="../../Scripts/jquery-1.5.2.min.js" type="text/javascript"></script>
    <script src="../../Scripts/js/i18n/grid.locale-en.js" type="text/javascript"></script>
    <script src="../../Scripts/jquery.jqGrid.min.js" type="text/javascript"></script>
     <%-- End Add Code --%>
</head>

Next is we would be injecting a jqGrid in the page. For this sample we would be modifying the index.aspx in the Home View as pre-created in a ASP.NET MVC application.

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<StepByStepJQGridGuid.ViewModel.HomeViewModel>" %>
<%@ Import Namespace="StepByStepJQGridGuid.Helper" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Home Page
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <%: Html.CreateJQGrid<StepByStepJQGridGuid.ViewModel.ProductViewModel>(Model.GridData)%>
</asp:Content>

As shown above we need a Html.CreateJQGrid helper to create the jqgrid, we also need to import the namespace of the helper class to the page (e.g. <%@ Import Namespace=”StepByStepJQGridGuid.Helper” %>). Below you’ll see that where using a grid model (GridViewModel<T>) which wraps the object that would define the grid column definitions(e.g. column width, alignment etc), the grid model itself defines the jqGrid main definitions (e.g. Id,Caption,Url,Grid Width etc).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Text;
using StepByStepJQGridGuid.ViewModel;

namespace StepByStepJQGridGuid.Helper
{
    public static class HtmlHelperExtensions
    {
        public static MvcHtmlString CreateJQGrid<T>(this HtmlHelper helper, GridViewModel<T> model)
        {
            var htmlBuilder = new StringBuilder();

            htmlBuilder.AppendFormat(@"<table id=""{0}"" class=""scroll"" cellpadding=""0"" cellspacing=""0""></table>", model.Id);
            htmlBuilder.AppendFormat(@"<div id=""{0}Pager"" class=""scroll"" style=""text-align:center;""></div>", model.Id);

            htmlBuilder.AppendFormat(@"<script type=""text/javascript"">");
            htmlBuilder.AppendFormat(@"$(function()");
            htmlBuilder.AppendFormat(@"{{");
            htmlBuilder.AppendFormat(@"$('#{0}').jqGrid({{", model.Id);
            htmlBuilder.AppendFormat(@"url: '{0}',", model.Url);
            htmlBuilder.AppendFormat(@"datatype: 'json',");
            htmlBuilder.AppendFormat(@"mtype: 'POST',");

            //Create Columns
            htmlBuilder.AppendFormat(@"colModel: [");
            foreach (var column in model.Columns)
            {
                htmlBuilder.AppendFormat(@"{{ name: '{0}', 
                                            index: '{0}', 
                                            width: {1}, 
                                            align: '{2}', 
                                            sortable: {3},
                                            hidden: {4}
                }},", column.Name
                    , column.Width > 0 ? column.Width : 80
                    , column.Align == null ? "left" : column.Align.ToLower()
                    , column.IsSortable.ToString().ToLower()
                    , column.IsHidden.ToString().ToLower()
                    );
            }
            htmlBuilder.AppendFormat(@"],");

            htmlBuilder.AppendFormat(@"pager: jQuery('#{0}Pager'),", model.Id);
            htmlBuilder.AppendFormat(@"rowNum: 5,");
            htmlBuilder.AppendFormat(@"rowList: [5, 10, 20, 50],");
            htmlBuilder.AppendFormat(@"viewrecords: true,");
            htmlBuilder.AppendFormat(@"imgpath: '/scripts/themes/coffee/images',");
            htmlBuilder.AppendFormat(@"caption: '{0}',", model.Caption);
            htmlBuilder.AppendFormat(@"width: {0}", model.Width);
            htmlBuilder.AppendFormat(@"}});");
            htmlBuilder.AppendFormat(@"}});");
            htmlBuilder.AppendFormat(@"</script>");


            return MvcHtmlString.Create(htmlBuilder.ToString());
        }
    }
}

Below shows the object represented within the jqGrid, it is designed to contain attributes (e.g. JQGridColumn) which would be used as the column definitions.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using StepByStepJQGridGuid.Utilities;

namespace StepByStepJQGridGuid.ViewModel
{
    public class ProductViewModel
    {
        [JQGridColumn(IsHidden = true)]
        public int ProductID { get; set; }
        [JQGridColumn(Width = 200, Align = "Center")]
        public string Name { get; set; }
        [JQGridColumn(Width = 50, Align = "Left")]
        public string ProductNumber { get; set; }
        [JQGridColumn(Width = 50, Align = "Right")]
        public decimal ListPrice { get; set; }
    }
}

Below is the attribute class, to learn more about attributes visit here.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace StepByStepJQGridGuid.Utilities
{
    [AttributeUsage(AttributeTargets.Property)]
    public class JQGridColumnAttribute : Attribute
    {
        public int Width { get; set; }
        public string Align { get; set; }
        public bool IsSortable { get; set; }
        public bool IsHidden { get; set; }
    }
}

Lastly, is the GridViewModel itself, the class uses reflection to retrieve the attributes from the object.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using StepByStepJQGridGuid.Utilities;

namespace StepByStepJQGridGuid.ViewModel
{
    public class GridViewModel<T>
    {
        public GridViewModel()
        {
            this.Data = new List<T>();
            CreateColumns();
        }

        public string Id { get; set; }
        public string Url { get; set; }
        public string Caption { get; set; }
        public int Width { get; set; }
        public List<T> Data { get; set; }
        public IEnumerable<JQGridColumn> Columns { get; set; }

        private void CreateColumns()
        {
            var modelType = typeof(T);
            var columns = new List<JQGridColumn>();

            var properties = modelType.GetProperties();
            if (properties != null)
            {
                foreach (var property in properties)
                {
                    var column = new JQGridColumn();
                    column.Name = property.Name;

                    var attrs = Attribute.GetCustomAttributes(property);
                    foreach (var attr in attrs)
                    {
                        var a = attr as JQGridColumnAttribute;
                        if (a != null)
                        {
                            column.Width = a.Width;
                            column.IsHidden = a.IsHidden;
                            column.IsSortable = a.IsSortable;
                            column.Align = a.Align;
                        }
                    }
                    columns.Add(column);
                }
            }
            Columns = columns;
        }
    }
}

Now we will proceed with modifying the Homecontroller, as a standard, we would be making the Home View strongly typed to a ViewModel (e.g. HomeViewModel). Then we would be using the ViewModel to pass data from Controller to View.

Below is the ViewModel:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace StepByStepJQGridGuid.ViewModel
{
    public class HomeViewModel
    {
        public HomeViewModel() 
        {
            //Grid Definitions
            this.GridData = new GridViewModel<ProductViewModel>();
            this.GridData.Url = "/Home/GridData";
            this.GridData.Id = "ProductSearchGrid";
            this.GridData.Width = 800;
            this.GridData.Caption = "Products";
        }

        public GridViewModel<ProductViewModel> GridData { get; set; }
    }
}

Next we will modify the home controller as shown below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using StepByStepJQGridGuid.ViewModel;

namespace StepByStepJQGridGuid.Controllers
{
    [HandleError]
    public class HomeController : Controller
    {
        public HomeController() 
        {
        }

        public ActionResult Index()
        {
            var model = new HomeViewModel();

            if(Session["cacheProducts"] == null)
                Session["cacheProducts"] = CreateDummyProducts(500).OrderBy(x => x.ProductID).ToList();
            
            return View(model);
        }

        public ActionResult GridData(string sidx, string sord, int page, int rows)
        {
            var cacheProducts = Session["cacheProducts"] as List<ProductViewModel>;
            var totalRecords = cacheProducts.Count;
            var products = cacheProducts.Skip((page - 1) * rows).Take(rows);

            var pageIndex = Convert.ToInt32(page) - 1;
            var pageSize = rows;
            var totalPages = (int)Math.Ceiling(totalRecords / (float)pageSize);
 
            var jsonData = new
            {
                total = totalPages, 
                page = page,
                records = totalRecords, 
                rows = (
                    from p in products
                    select new {
                        i = p.ProductID,
                        cell = new[] { p.ProductID.ToString(), p.Name, p.ProductNumber, p.ListPrice.ToString() }
                    }).ToArray()
            };

            return Json(jsonData);
        }

        public ActionResult About()
        {
            return View();
        }

        private List<ProductViewModel> CreateDummyProducts(int count) 
        {
            var products = new List<ProductViewModel>();
            for (var i = 0; i < count; i++) 
            {
                var product = new ProductViewModel();
                product.ProductID = i + 1;
                product.Name = "Product" + i.ToString() + "_" + Guid.NewGuid().ToString();
                product.ProductNumber = "PN" + i.ToString();
                product.ListPrice = i * 21;
                products.Add(product);
            }
            return products;
        }
    }
}

To try it out yourself, download a copy of the test project below, Thanks!
https://skydrive.live.com/embedicon.aspx/Shared/StepByStepJQGridGuid.zip?cid=34106e8cbacbd842&sc=documents

Advertisements

5 responses to “ASP.NET MVC, C#: Custom jqGrid object based column definitions

  1. Pingback: ASP.NET MVC, C#: Custom jqGrid object based column definitions (via lbrt.NET) « Rado's Blog

  2. Fung 2011/10/12 at 2:44 AM

    Good job!

  3. Pingback: ASP.NET MVC, C#: Custom jqGrid object based column definitions (via lbrt.NET) | idispose.net

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: