Hello world!

Welcome to WordPress.com. This is your first post. Edit or delete it and start blogging!

Posted in Uncategorized | 1 Comment

Implementing jqGrid PlugIn with ASP.NET MVC

I would suggest before getting started is to have some knowledge of the following. I wanted to first say thank you Phil Haack and his BLOG entry over at Haacked click here.

 

Here are a few steps to get a project started.

  1. Create a ASP.NET MVC 2 or 1 Web Application.
  2. Add jQuery, jqGridPlugIn, and the theme of your choice to the application,
    1. Open the Them Roller pick your theme. I chose Start
    2. Click Download and place the jquery-ui-custom file on you hard drive.
    3. Make sure to select everything as to not to miss something for themes.
    4. After downloading unzip the file and open the folder CSS.
    5. In the CSS folder you will see a folder with the name of the theme, because I chose the Start theme I have a folder called Start.
    6. Copy the subfolder in CSS theme folder into the Content folder of the MVC project.
    7. The rest of the files in the jquery-ui-custom zip you don’t need.
    8. Download jqGrid PlugIn and unzip.
    9. Copy the i18n and the local will use into the Scripts folder.
    10. Copy the jquery.jqGrid.min.js into the scripts folder.
    11. Copy the ui.jqgrid.css into the Content folder.
    12. image
    13. image
  3. Modify the Site.Master file to include jQuery. If you want you can get the latest version, but I’m going with jQuery 1.4.1 which comes with ASP.NET MVC 2
  4. Modify the Site.Master file to include the jQuery Them CSS file. For my sample I’m including the in Contentstatjquery-ui-1.8.custom.css
  5. Modify the Site.Master file to have a Content Place Holder for JavaScript.

After you are done Site.Master file will look similar to this.

Code Snippet
  1.    .
  2.    .
  3.    .
  4. <head runat="server">
  5.     <title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
  6.     <link href="../../Content/Site.css" rel="stylesheet" type="text/css" />
  7.  
  8.     <script src="../../Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
  9.     <link href="../../Content/start/jquery-ui-1.8.custom.css" rel="stylesheet" type="text/css" />
  10.     <asp:ContentPlaceHolder ID="ScriptContent" runat="server" />
  11. </head>
  12.    .
  13.    .
  14.    .

 

When it comes to the AdventureWorks database and setting it up I’m going to make the assumption that is not a challenge. I’m going to use the SalesOrderHeader table from the database to build the grid from. I’m going to create a Data layer in the web Application, a data context, and a repository to read the records from the database.

  1. Create a folder and name it Data
  2. Add a New Item to the folder choose LINQ to SQL Classes
  3. Name the file AdventureWorks
  4. Add the table SalesOrderHeader to the DataContext design.
  5. Add a Class to the folder and name it SalesOrderHeaderRepository
  6. image

The ground work is in place now what we need to do is figure out what jqGrid does to get the data. This is where the documentation takes a dive. There is documentation on a URL you must setup for jqGrid to work. The is no explanation as to what parameters are passed to that URL and had to use those parameters to get the expected data. The only documentation that I have found that explains the parameters is here, but you need to scroll down to the prmNames section to see it. Another good example although not documentation, but you can see an explanation of the parameters in a PHP sample

Code Snippet
  1. $page = $_GET['page']; // get the requested page
  2. $limit = $_GET['rows']; // get how many rows we want to have into the grid
  3. $sidx = $_GET['sidx']; // get index row – i.e. user click to sort
  4. $sord = $_GET['sord']; // get the direction

 

From that we can see that a  the page of data requested along with how may rows of data we need to get.  These two parameters are called page and rows. Also being passed is the column to sort on and the direction to sort in. I will not get into sorting, but there are some good blog entries on how to implement that with dynamic LINQ (Thank you Phil). Now that we have the requirements down we need to build a method in our Sales Order Header Repository that will return paged data and only return a set number of records.

  1. Open the SalesOrderHeaderRepository.cs file and past the following
Code Snippet
  1. /// <summary>
  2. /// Gets the sales orders starting at the specified page and return
  3. /// specified number of rows.
  4. /// </summary>
  5. /// <param name="page">The page to start getting sales order.</param>
  6. /// <param name="rows">The number of rows to get.</param>
  7. /// <returns>
  8. /// The specified number of sales orders rows at the specfied page.
  9. /// </returns>
  10. public IEnumerable<SalesOrderHeader> GetSalesOrders(int page, int rows)
  11. {
  12.     using (var dataContext = new AdventureWorksDataDataContext())
  13.     {
  14.         int startRow = page * rows;
  15.         var results = dataContext.SalesOrderHeaders.Skip(startRow).Take(rows);
  16.         foreach(var result in results)
  17.         {
  18.             yield return result;
  19.         }
  20.     }
  21. }

 

One of the blessing of using ASP.NET 3.x is the routing and method calling done before creating a web page. Knowing how the routing works we can use a URL in for jqGrid PlugIn that calls an Action inside a Controller. It should be easy to create a method knowing that the Action mimics the same named parameters of the URL. Pulling together this knowledge of the parameters used by jqGrid PlugIn and how the parameters for an Action works you can create Controller class with methods to handle the request of the jqGrid.

  1. Add to the Controllers folder a Controller and name it GridController
  2. Create a Method in the controller that will return the data using the methods required by jqGrid
Code Snippet
  1. public ActionResult GridData(string sidx, string sord, int page, int rows)
  2. {
  3.     
  4. }

 

Now we need to use the repository to get the data based on the what is passed in and return the results as JSON. Let us start by looking at the requirements for the JSON results. You will see that a requirement is a count of total number of records.

Code Snippet
  1. {
  2.   total: "xxx",
  3.   page: "yyy",
  4.   records: "zzz",
  5.   rows : [
  6.     {id:"1", cell:["cell11", "cell12", "cell13"]},
  7.     {id:"2", cell:["cell21", "cell22", "cell23"]},
  8.       …
  9.   ]
  10. }

There are many was to go about doing this, but for a quick and dirty way I’m just going to fulfill this requirement by adding a method to the repository that returns the total number of records. Later on this can become useful if there are filters applied then the method can be modified to count only the records base on a filter.

  1. Open the SalesOrderHeaderRepository.cs file and past the following

Code Snippet
  1. /// <summary>
  2. /// Gets the number of sale orders.
  3. /// </summary>
  4. /// <returns>The number of sale orders</returns>
  5. public int GetNumberOfSalesOrder()
  6. {
  7.     int numberOfRecords = 0;
  8.     using (var dataContext = new AdventureWorksDataDataContext())
  9.     {
  10.         numberOfRecords = dataContext.SalesOrderHeaders.Count();
  11.     }
  12.  
  13.     return numberOfRecords;
  14. }

We can now build out the method in the controller now that we have all the supporting pieces.

  1. Open the GridController.cs
  2. Add a using to the Data layer
  3.  
    Code Snippet
    1. using jqGridDemo.Data;

  4. Update the method to the following

Code Snippet
  1. public JsonResult GridData(string sidx, string sord,  int page, int rows)
  2.         {
  3.             var repository = new SalesOrderRepository();
  4.             
  5.             int pageIndex = page – 1;
  6.             int pageSize = rows;
  7.             int totalRecords = repository.GetNumberOfSalesOrder();
  8.             int totalPages = (int)Math.Ceiling((float)totalRecords / (float)pageSize);
  9.  
  10.             var jsonData = new
  11.             {
  12.                 total = totalPages,
  13.                 page = page,
  14.                 records = totalRecords,
  15.                 rows = (
  16.                     from salesOrder in repository.GetSalesOrders(pageIndex, rows)
  17.                     select new
  18.                     {
  19.                         i = salesOrder.SalesOrderID,
  20.                         cell = new string[] {
  21.                             salesOrder.SalesOrderNumber,
  22.                             salesOrder.OrderDate.ToShortDateString(),
  23.                             salesOrder.DueDate.ToShortDateString(),
  24.                             salesOrder.TotalDue.ToString("###,###,##0.00")
  25.                         }
  26.                     }
  27.                 ).ToArray()
  28.             };
  29.  
  30.             return Json(jsonData);
  31.         }

I wont get into all the nuts and bolts of the logic you can take a look at the blogs mentioned above. Suffice to say that this will grab the data just the page of data from the database and return back a JSON Action Result.

The final piece to the puzzle is the HTML page. We will utilize the Content Placer we created in the Site.Master to hold the JavaScript. Some of the key options of the jqGrid PlugIn is the URL which is in the form of the default ASP.NET Routings which is /Controller/Action. You will also see that the data type is JSON. Finally and the most important one is the method type which is POST. With ASP.MVC 2 returning JSON results from a GET method type is not allowed by default because of security. Instead of use a GET as method to the call I changed it to use POST. I know the REST people are getting upset.

 

Code Snippet
  1. <%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>
  2.  
  3. <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
  4.     Home Page
  5. </asp:Content>
  6. <asp:Content ID="script" ContentPlaceHolderID="ScriptContent" runat="server">
  7.     <link href="../../Content/ui.jqgrid.css" rel="stylesheet" type="text/css" />
  8.     <script src="../../Scripts/i18n/grid.locale-en.js" type="text/javascript"></script>
  9.     <script src="../../Scripts/jquery.jqGrid.min.js" type="text/javascript"></script>
  10.  
  11. <script type="text/javascript">
  12.     jQuery(document).ready(function() {
  13.         jQuery("#list").jqGrid({
  14.             url: ‘/Grid/GridData’,
  15.             datatype: ‘json’,
  16.             mtype: ‘POST’,
  17.             colNames: ['Order Number', 'Order Date', 'Due Date', 'Amount'],
  18.             colModel: [
  19.               { name: 'salesordernumber', index: 'salesordernumber', width: 200 },
  20.               { name: 'orderdate', index: 'orderdate', width: 200 },
  21.               { name: 'duedate', index: 'duedate', width: 200 },
  22.               { name: 'totaldue', index: 'tax', width: 200 }
  23.             ],
  24.             pager: ‘#pager’,
  25.             rowNum: 20,
  26.             rowList: [20, 40, 80],
  27.             sortname: ‘invid’,
  28.             sortorder: ‘desc’,
  29.             viewrecords: true,
  30.             caption: ‘My first grid’,
  31.             height: "300"
  32.             
  33.         });
  34.     });
  35. </script>
  36.  
  37. </asp:Content>
  38. <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
  39.  
  40. <table id="list"></table>
  41. <div id="pager"></div>
  42.  
  43. </asp:Content>

 

It is with hope that by stumbling through this and the other posts on the web you will be able to implement jqGrid PlugIn into ASP.NET MVC.

image

Posted in Uncategorized | 1 Comment

Live Lab Pivot is Available to All

Pivot is now available to all who want to participate in the experiment. You can download it over at Get Pivot!

Posted in Uncategorized | Leave a comment

SQLSaturday #34 Boston 2010

If you are in the Boston area on January 30th 2010 check out the SQLSaturday #34. Matt will be be doing some demos on Pivot.

Pivot Data Visualization
Live Labs recently released Pivot a tool to visualize data which can allow uses to see patterns in data like never before. In this session I will provide a basic intro to Pivot and discuss how to use you existing database and the Pivot Collection Tools SDK that I have released to dynamically build Pivot Collections.

- Matt

Posted in Uncategorized | Leave a comment

TileBuilder Now Working

One other possibility is that I’m using the logic wrong. The image list needs to be reorder into Morton Layout column major.

This is the test method

 

Code Snippet
  1. [TestMethod]
  2. public void Build_Tile_For_Zoom_Level_5_Row_0_Column_0()
  3. {
  4.     // Location of the images.
  5.     string imagePath = @"D:DataImages";
  6.  
  7.     // Sequential list used to store the file names.
  8.     var rawSequentialImageList = new List<string>();
  9.  
  10.     // Build a sequential list of the images
  11.     for(int imageCount = 0; imageCount < 24; imageCount++)
  12.     {
  13.         string fileName = string.Concat(imageCount, ".jpg");
  14.         fileName = Path.Combine(imagePath, fileName);
  15.         rawSequentialImageList.Add(fileName);
  16.     }
  17.  
  18.     // List used to store the file names in Morton Layout column major.
  19.     var mortonImageList = new List<ImageBag>();
  20.  
  21.     // List of morton number used as indexes to the sequential list.
  22.     var numberList = new List<int>(TileBuilder.GetTileIds(24, 5, 0, 0, 256));
  23.     
  24.     // Iterate thru the morton numbers reordering the raw image list into the
  25.     // mortonImageList.
  26.     foreach (var mortonNumber in numberList)
  27.     {
  28.         string fileName = rawSequentialImageList[mortonNumber];
  29.         mortonImageList.Add(new ImageBag(fileName));
  30.     }
  31.  
  32.     // Create the tile image based on the reorder image list.
  33.     TileBuilder.CreateTileImage(mortonImageList, 5, 0, 0, "..\..\..\");
  34. }

 

This is the output which looks identical to the control image in my previous post.

Correct_5_0_0

Posted in Uncategorized | Leave a comment

It Looks Good, But Not The Right Pattern

I got a bit side track on the TileBuilder because of a sorting issue that could be chalked up as a documentation error not a bug. I have my control images built for testing the expected layout of the TileBuilder. I built a series of images to represent the numbers from 0 to 24. I have also grouped the numbers into 3 groups, creating a 3 grids 4×4 each. I colored each group a different color as to stand out (Red, Green, Blue). I used the SeaDragon API to create a DZC as a reference point. In theory the TileBuilder logic should create the same results.

0_0

This is the control image built by SeaDragon API. This is Zoom Level 5 Row 0 Column 0. You can see the 4×4 groups in the various colors. You can also see (although a bit blurry) the Morton Layout.

And here is what I get with TileBuilder

5_0_0

Well I was correct that the pattern looks good but the expected out is not correct.

Posted in Uncategorized | Leave a comment

I think I got the TileBuilder for Dynamic Collections

I believe this is it. I’m in the process of creating images that at any zoom level you can tell which is which. It is difficult to see if the individual rows and columns have different images. I’m going to make images with solid colors with the hopes I can tell one from the other.

 

 3_0_0 4_0_0 5_0_0 6_0_0

Posted in Uncategorized | Leave a comment