Sunday 13 November 2011

Qtip integration with JqGrid in ASP.NET MVC


Introduction:
In this article I am going to demonstrate with code example how to integrate qtip with JqGrid in asp.mvc application. This is a generic implementation in a way that you simply set a custom property named “description” in ColModel  to whatever you want to display in tooltip such as text, images and server side data etc.
To understand this example effectively I will assume that you have the basic knowledge of JqGrid  (http://www.trirand.com/blog/), QTip (http://craigsworks.com/projects/qtip/)  and ASP.NET MVC (http://www.asp.net/mvc).

Create a new ASP.NET MVC Application:

In visual studio 2010 sp1 go to
File -> Project ->



Select “web” under Visual C# then choose ASP.NET MVC 3 Web Application and change the name of the solution to “JqGridWithQTipIntegration”.
In next step let the options selected as default with “Internet Application” and “view engine as .aspx”.
Click Ok button to create new asp.net mvc 3 web application.
After project creation you are going to have following hierarchy in solution explorer.

Build a custom Model for Demo:

In model folder in asp.net mvc web application add new classes named as “SomeEntity.cs” and “Repository.cs”.
SomeEntity.cs
  public class SomeEntity
    {
        public int Id { get; set; }
        public int IntProperty { get; set; }
        public string StringProperty { get; set; }
        public DateTime DateProperty { get; set; }
    }

Repository.cs
/// <summary>
    /// Trivial repository of random data for demo purposes. Not for use in a real application!
    /// </summary>
    public class Repository
    {
        private static IQueryable<SomeEntity> _data;

        public IQueryable<SomeEntity> SelectAll()
        {
            return _data;
        }

        /// <summary>
        /// Demo data is static so that we can demonstrate sorting with the same data for the whole lifetime of the application.
        /// </summary>
        static Repository()
        {
            var data = new List<SomeEntity>();
            var rand = new Random();
            for (int i = 0; i < 100; i++)
            {
                data.Add(new SomeEntity
                    {
                        Id = i,
                        IntProperty = rand.Next(99),
                        StringProperty = rand.Next(99).ToString(),
                        DateProperty = new DateTime(2000 + rand.Next(10), rand.Next(11) + 1, rand.Next(27) + 1)
                    });
            }
            _data = data.AsQueryable();
        }
    }

Add ActionMethod in HomeController that will return server side data for JqGrid:

Add following Action Method in Home Controller. This will return server side data to bind JqGrid which is of type Json and it will take parameters which JqGrid send with ajax request as shown below.
(link for jqgrid default parameters with ajax request)
public ActionResult GridDemoData(int page, int rows, string search, string sidx, string sord)
        {
            int currentPage = Convert.ToInt32(page) - 1;
            int totalRecords = 0;
            var repository = new Repository();
            var data = repository.SelectAll();
            totalRecords = data.Count();
            var totalPages = (int)Math.Ceiling(totalRecords / (float)rows);
            var jsonData = new
            {
                total = totalPages,
                page,
                records = totalRecords,

                rows = (
                           from m in data
                           select new
                           {
                               id = m.Id,
                               cell = new object[]
                                                                            {
                                                                            
                                                                                m.IntProperty,
                                                                                m.StringProperty,
                                                                                String.Format("{0:MM/dd/yyyy}", m.DateProperty)
                                                                            }
                           }).ToArray()
            };
            return Json(jsonData, JsonRequestBehavior.AllowGet);

        }

JqGrid and Qtip Setup Requirements:

You need to include following files in Site.Master to implement solution.
·         ui.jqgrid.css is used for jqgrid style and formatting
·         jquery-ui-1.8.custom.css used for style and formatting
·         jquery-1.5.1.min.js used for jquery framework
·         jquery-ui-1.8.7custom.min.js used for jquery ui like dialog etc.
·         grid.locale-en.js used for jqgrid localization
·         jquery.jqGrid.min.js required for jqgrid
<link href="<%= ResolveUrl("~/Content/themes/redmond/ui.jqgrid.css") %>" rel="stylesheet"
        type="text/css" />
    <link href="<%= ResolveUrl("~/Content/Site.css") %>" rel="stylesheet" type="text/css" />
    <link href="<%= ResolveUrl("~/Content/themes/redmond/jquery-ui-1.8.custom.css") %>"
        rel="stylesheet" type="text/css" />
    <script src="<%: Url.Content("~/Scripts/jquery-1.5.1.min.js") %>" type="text/javascript">
    </script>
    <script src="../../Scripts/jquery-ui-1.8.7custom.min.js" type="text/javascript"></script>
    <script src="../../Scripts/grid.locale-en.js" type="text/javascript"></script>
    <script src="../../Scripts/jquery.jqGrid.min.js" type="text/javascript"></script>

Note: order of files included is important because if you change the order then JqGrid will not be operational.

JqGrid configuration:

Below is JavaScript and HTML code for JqGrid.
·         HTML elements added for JqGrid in Index.aspx
<table id="grid" cellpadding="0" cellspacing="0">
        </table>
        <div id="pager" style="text-align: center;">
        </div>
        <div id="search" style="margin-left: 30%; display: none">
        </div>

·         JavaScript code for JqGrid in Home.GridDemo.js
var lastsel;
$(function () {

    $("#grid").jqGrid({
        colNames: ['Int', 'String', 'Date'],
        colModel: [
                        { name: 'IntProperty', index: 'IntProperty', sortable: true,
                            editable: true, editoptions: { dataInit: ShowHint },
                            description: 'IntProperty tooltip goes here'
                        },
                        { name: 'StringProperty', index: 'StringProperty', sortable: true,
                            editable: true, editoptions: { dataInit: ShowHint },
                            description: 'StringProperty tooltip goes here'
                        },
                        { name: 'DateProperty', index: 'DateProperty', sortable: true,
                            editable: true, editoptions: { dataInit: ShowHint },
                            description: 'DateProperty tooltip goes here'
                        },
                      ],
        pager: $("#pager"),
        sortname: 'IntProperty',
        rowNum: 10,
        rowList: [10, 20, 50],
        sortorder: "",
        height: 300,
        imgpath: '/Content/jqGridCss/redmond/images',
        width: 800,
        url: "/Home/GridDemoData",
        datatype: 'json',
        mtype: 'GET',
        onCellSelect: function (rowid, iCol, aData) {


            if (rowid && rowid !== lastsel) {

                if (lastsel)
                    jQuery('#grid').jqGrid('restoreRow', lastsel);
                jQuery('#grid').jqGrid('editRow', rowid, true);
                lastsel = rowid;
            }
        }
    }).navGrid($("#pager"), { edit: true, add: false, del: false, search: false });
    $("#search").filterGrid($("#grid"), {
        gridModel: false,
        filterModel: [{
            label: 'Search',
            name: 'search',
            stype: 'text'
        }]
    });
});


Note that “description” is a custom property which contains text for tooltip and “ShowHint” method is called to display description text as a tooltip.

Generic Implementation of JqGrid integration with QTip:

Below is the code for JqGrid integration with Qtip in Helper.js
// this function show tool tip dialog for a certain element of jqgrid and assumes that jqgrid name is #grid
function ShowHint(elem) {
    var selector = '';

    if (this.gridName != null)
        selector = '#' + this.gridName;
    else if ($('#grid') != null) {
        selector = '#grid';

    }

    if (selector == '') {
        alert('jqgrid name is not "grid" or gridName "Edit Option" not set');
        return;

    }

    if (elem == 0)
        return;

    jQuery(elem).qtip({
        content: getColDescription(this.name, selector),
        show: 'focusin',
        hide: 'focusout',
        style:
    {

        name: 'red',
        tip: 'leftTop',
        textAlign: 'left',
        fontWeight: '500',
        fontSize: '11px'

    },
        position:
    {
        corner:
        {
            target: 'rightTop',
            tooltip: 'LeftTop'

        }
    }
    });
}

function getColDescription(colName, jqGridSelector) {
    var description = '';
    if (colName != '') {
        var colModel = $(jqGridSelector).getGridParam('colModel');
        $.each(colModel, function (index, model) {
            if (model.name == colName) {
                description = model.description;
                return false;
            }

        });
    }


    return description;
}

Web Page working Example:


You can download complete demo code with link provided.
http://code.google.com/p/jqgridwithqtipintegration/downloads/list

Sunday 23 October 2011

Factory Design Pattern C# Code example




Introduction:

It separates the object creational logic and reduces coupling between classes. Usually, when there are multiple classes inheriting from same base class, it is recommended to use a factory design pattern.

Noob implementation:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Factory
{
    public abstract class DbServer
    {
        //method need to be implemented by inherited classes
        public abstract string GetDbServerName();
    }
    public class MsSqlServerDb : DbServer
    {
        //overridden method
        public override string GetDbServerName()
        {
            return "MS Sql Server";
        }
    }
    public class OracleDb : DbServer
    {
        //overridden method
        public override string GetDbServerName()
        {
            return "Oracle Database Server";
        }
    }
    //factory class that will be used to create objects
    public static class DatabaseFactory
    {
        //return the required object
        public static DbServer GetDb(string DbName)
        {
            if (DbName == "Ms Sql Server")
            {
                return new MsSqlServerDb();
            }
            if (DbName == "Oracle Database Server")
            {
                return new OracleDb();
            }
            return new MsSqlServerDb();

        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            //get the ms sql server object
            DbServer dbServer = DatabaseFactory.GetDb("Ms Sql Server");
            //return ms sql server
            string dbName = dbServer.GetDbServerName();
            //print the name on output window
            Console.WriteLine("Server Name : " + dbName);
            //get the oracle database server object
            dbServer = DatabaseFactory.GetDb("Oracle Database Server");
            //return oracle server name
            dbName = dbServer.GetDbServerName();
            //print the name to output window
            Console.WriteLine("Server Name : " + dbName);
            Console.Read();
        }
    }
}




Noob implementation does not adhere to OPEN/CLOSE PRINCIPLE, which states that classes should be open for extension but modification, should not be allowed.

To overcome this issue, we can use “class registration approach," implementation as below.


Class Registration:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Factory
{
    public abstract class DbServer
    {
        //method need to be implemented by inherited classes
        public abstract string GetDbServerName();
        public abstract DbServer CreateDbServer();
    }
    public class MsSqlServerDb : DbServer
    {
        //overridden method
        public override string GetDbServerName()
        {
            return "MS Sql Server";
        }

        public override DbServer CreateDbServer()
        {
            return new MsSqlServerDb();
        }
        public static void RegisterDbServer(string dbName)
        {
            DatabaseFactory.RegisterDatabaseServer(dbName, new MsSqlServerDb());
        }
    }
    public class OracleDb : DbServer
    {
        //overridden method
        public override string GetDbServerName()
        {
            return "Oracle Database Server";
        }

        public override DbServer CreateDbServer()
        {
            return new OracleDb();
        }
        public static void RegisterDbServer(string dbName)
        {
            DatabaseFactory.RegisterDatabaseServer(dbName, new OracleDb());
        }
    }
    //factory class that will be used to create objects
    public static class DatabaseFactory
    {
        public static Dictionary<string, DbServer> dbDictionary = new Dictionary<string, DbServer>();
      
        public static void RegisterDatabaseServer(string dbName, DbServer dbServer)
        {
            dbDictionary.Add(dbName, dbServer);
        }

        public static DbServer GetDb(string DbName)
        {
            DbServer dbServer = new MsSqlServerDb();
            if (dbDictionary.ContainsKey(DbName))
            {
                dbServer = dbDictionary[DbName];
                return dbServer.CreateDbServer();
            }
            return dbServer.CreateDbServer();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            //registeration
            MsSqlServerDb.RegisterDbServer("Ms Sql Server");
            OracleDb.RegisterDbServer("Oracle Database Server");

            //get the ms sql server object
            DbServer dbServer = DatabaseFactory.GetDb("Ms Sql Server");
            //return ms sql server
            string dbName = dbServer.GetDbServerName();
            //print the name on output window
            Console.WriteLine("Server Name : " + dbName);
            //get the oracle database server object
            dbServer = DatabaseFactory.GetDb("Oracle Database Server");
            //return oracle server name
            dbName = dbServer.GetDbServerName();
            //print the name to output window
            Console.WriteLine("Server Name : " + dbName);
            Console.Read();
        }
    }
}