An easy subject this time. To configure subgrid we need to add few parameters to grid initialization code:
<script type="text/javascript">
  $(document).ready(function() {
    $('#jqgOrders').jqGrid({
      //url from wich data should be requested
      url: '/Home/OrdersGridData/',
      //type of data
      datatype: 'json',
      //url access method type
      mtype: 'GET',
      //columns names
      colNames: ['OrderID', 'Customer', 'Employee', 'OrderDate', 'RequiredDate', 'ShippedDate', 'ShipCountry'],
      //columns model
      colModel: [
                  { name: 'OrderID', index: 'OrderID', align: 'left' },
                  { name: 'Customer', index: 'CustomerID', align: 'left' },
                  { name: 'Employee', index: 'EmployeeID', align: 'left' },
                  { name: 'OrderDate', index: 'OrderDate', align: 'left' },
                  { name: 'RequiredDate', index: 'RequiredDate', align: 'left' },
                  { name: 'ShippedDate', index: 'ShippedDate', align: 'left' },
                  { name: 'ShipCountry', index: 'ShipCountry', align: 'left' }
                ],
      //pager for grid
      pager: $('#jqgpOrders'),
      //number of rows per page
      rowNum: 10,
      //initial sorting column
      sortname: 'OrderID',
      //initial sorting direction
      sortorder: 'asc',
      //we want to display total records count
      viewrecords: true,
      //grid width
      width: 'auto',
      //grid height
      height: 'auto',
      //enable subgrid
      subGrid: true,
      //subrid model
      subGridModel: [{
                       //subgrid columns names
                       name: ['ProductName', 'UnitPrice', 'Quantity', 'Discount'],
                       //subgrid columns widths
                       width: [200, 100, 100, 100],
                       //subrig columns aligns
                       align: ['left', 'left', 'left', 'left']
                     }],
      //url from which subgrid data should be requested
      subGridUrl: '/Home/OrdersDetailsSubgridData/'
    });
  });
</script>

Controller action for main grid is pretty standard (you can take a look at corresponding sample in jqGrid basics post). The one for subgrid is slightly different. That's because of  the different data format - subgrid takes only rows collection with cell table inside.
/// <summary>
///
Provides json data for jqGrid subgrid
/// </summary>
/// <param name="id">
parent row id</param>
/// <returns>json data</returns>
public ActionResult OrdersDetailsSubgridData(string id)
{
  //Preparing anonymous variable with json data
  var ordersDetails = new
  {
    rows = (from orderDetails in _repository.GetOrderDetails(Convert.ToInt32(id))
            select new
            {
              //table of cells values
              cell = new string[] {
                                    orderDetails.Product.ProductName,
                                    orderDetails.UnitPrice.ToString(),
                                    orderDetails.Quantity.ToString(),
                                    orderDetails.Discount.ToString()
                                  }
            }
           ).ToArray()
  };

  //Returning json data
  return Json(ordersDetails);
}

Subgrid is very limited (no support for paging, sorting, searching and editing). There is a solution which uses some of the subgrid functions of the main grid to create not a subgrid, but another fully functional grid. This solution is well described here and I'm not going to dig into it (it's just a little bit tricky initialization javascript). Let's take a look at standard subgrid we have created:

Of course you can download sample application here.

As promised, it's time to go ahead with a CRUD scenario for jqGrid.
Of course, we need to do some configuration first. We must define which columns are editable. For ones we will set type of edit field (through edittype parameter). We can also set some options for the edit field (editoptions) like maxlength for 'text' or dataUrl for 'select' (we will use the same actions for providing selects markup as in searching sample). Grid provides as also some validation support, which can be configured through editrules option. Be aware, that options we use in our example are only a small subset of what jqGrid allow us to configure, so I strongly advice reading the documentation.
Ok, let's initialize our grid:
<script type="text/javascript">
  $(document).ready(function() {
    $('#jqgProducts').jqGrid({
      //url from wich data should be requested
      url: '/Home/ProductsGridData/',
      //url for edit operation
      editurl: '/Home/EditProduct/',
      //type of data
      datatype: 'json',
      //url access method type
      mtype: 'GET',
      //columns names
      colNames: ['ProductID', 'ProductName', 'Supplier', 'Category', 'QuantityPerUnit', 'UnitPrice', 'UnitsInStock'],
      //columns model
      colModel: [
                  { name: 'ProductID', index: 'ProductID', align: 'left', width: 85, editable: false },
                  { name: 'ProductName', index: 'ProductName', align: 'left', width: 200, editable: true, edittype: 'text', editoptions: { maxlength: 40 }, editrules: { required: true } },
                  { name: 'Supplier', index: 'SupplierID', align: 'left', width: 225, formatter: supplierFormatter, unformat: supplierUnFormatter, editable: true, edittype: 'select', editoptions: { dataUrl: '/Home/SuppliersSelect' }, editrules: { required: true } },
                  { name: 'Category', index: 'CategoryID', align: 'left', width: 140, editable: true, edittype: 'select', editoptions: { dataUrl: '/Home/CategoriesSelect' }, editrules: { required: true } },
                  { name: 'QuantityPerUnit', index: 'QuantityPerUnit', align: 'left', editable: true, edittype: 'text', editoptions: { maxlength: 20 }, editrules: { required: true } },
                  { name: 'UnitPrice', index: 'UnitPrice', align: 'left', formatter: 'currency', formatoptions: { decimalSeparator: '.', thousandsSeparator: ',', decimalPlaces: 2, prefix: '$'}, editable: true, edittype: 'text', editrules: { required: true, number: true, minValue: 0 } },
                  { name: 'UnitsInStock', index: 'UnitsInStock', align: 'left', formatter: unitsInStockFormatter, unformat: unitsInStockUnFormatter, editable: true, edittype: 'text', editrules: { required: true, integer: true, minValue: 0, maxValue: 32767} }
                ],
      //pager for grid
      pager: $('#jqgpProducts'),
      //number of rows per page
      rowNum: 10,
      //initial sorting column
      sortname: 'ProductID',
      //initial sorting direction
      sortorder: 'asc',
      //we want to display total records count
      viewrecords: true
      //grid width
      width: 'auto'
      //grid height
      height: 'auto'
    });
  });
</script>

We are going to use a navigator as placeholder for add, edit and delete buttons, but it's not necessary. The buttons can be put anywhere on page, they just need to make proper API calls, which are well described in form editing documentation section.
For complete CRUD scenario, we need to prepare three operations. We will start with easiest one, which is deleting. All we have to do is enable delete button and set url for operation (in fact the url isn't necessary, all operations can use the editurl from initial configuration, but having seperate actions for each operation is a lot cleaner).
$('#jqgProducts').navGrid(
  '#jqgpProducts',
  //enabling buttons
  { add: false, del: true, edit: false, search: false },
  //edit options
  { },
  //add options
  { },
  //delete options
  { url: '/Home/DeleteProduct/' });

Delete request contains one parameter, which is row id value. In response we can send anything we want (or just nothing). If we sent something, we will receive it in afterSubmit event. Knowing that, we can prepare delete controller action:
/// <summary>
///
Deleting selected product
/// </summary>
/// <param name="id">
product id</param>
/// <returns>
json data</returns>
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult DeleteProduct(string id)
{
  //Deleting product
  bool success = _repository.DeleteProduct(Convert.ToInt32(id));

  //Returning data - we can hadle this data in form afterSubmit event
  return Json(success);
}

Let's move on to add operation. The client side part is pretty much the same (but remember, that jqGrid uses colModel options to build the form):
$('#jqgProducts').navGrid(
  '#jqgpProducts',
  //enabling buttons
  { add: true, del: true, edit: false, search: false },
  //edit options
  { },
  //add options
  { width: 'auto', url: '/Home/AddProduct/' },
  //delete options
  { url: '/Home/DeleteProduct/' });

On server side we receive a parameter for every editable field. We just need to make an object out of this and add it to repository:
/// <summary>
///
Adding product
/// </summary>
/// <param name="postData">
postData collection</param>
/// <returns>
json data</returns>
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddProduct(FormCollection postData)
{
  //Creating new product object based on postData
  Product product = new Product();
  product.ProductName = postData["ProductName"];
  product.SupplierID = Convert.ToInt32(postData["Supplier"]);
  product.CategoryID = Convert.ToInt32(postData["Category"]);
  product.QuantityPerUnit = postData["QuantityPerUnit"];
  product.UnitPrice = Convert.ToDecimal(postData["UnitPrice"].Replace(".", CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator));
  product.UnitsInStock = Convert.ToInt16(postData["UnitsInStock"]);
  product.Discontinued = false;

  //Adding product to repository
  bool success = _repository.AddProduct(product);

  //Returning data - we can hadle this data in form afterSubmit event
  return Json(success);
}

Last operation to implement is editing. There are two edit approaches to consider (actually there are three, but I'm going to skip cell editing): inline editing and form editing. In inline editing we are adding onSelectRow event handler in which we call editRow (for displaying edit controls) or saveRow (for posting new values to server) method:
$('#jqgProducts').setGridParam({
  onSelectRow: function(id){
    if(id && id != lastSel){
      //save changes in row
      $('#jqgProducts').saveRow(lastSel, false);
      lastSel=id;
    }
    //trigger inline edit for row
    $('#jqgProducts').editRow(id, true);
  }
});

Form editing works the same as adding. We just enable the button and then grid constructs the form based on colModel:
$('#jqgProducts').navGrid(
  '#jqgpProducts',
  //enabling buttons
  { add: true, del: true, edit: true, search: false },
  //edit options
  { width: 'auto' },
  //add options
  { width: 'auto', url: '/Home/AddProduct/' },
  //delete options
  { url: '/Home/DeleteProduct/' });

No matter which approach we choose, request looks the same. We are getting row id and values for all the editable fields. What we need to do is get object from repository and set new values:
/// <summary>
///
Editing product
/// </summary>
/// <param name="postData">
postData collection</param>
/// <returns>
json data</returns>
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult EditProduct(FormCollection postData)
{
  //Editing product based on postData
  Product product = _repository.GetProduct(Convert.ToInt32(postData["id"]));
  product.ProductName = postData["ProductName"];
  product.SupplierID = Convert.ToInt32(postData["Supplier"]);
  product.CategoryID = Convert.ToInt32(postData["Category"]);
  product.QuantityPerUnit = postData["QuantityPerUnit"];
  product.UnitPrice = Convert.ToDecimal(postData["UnitPrice"].Replace(".", CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator));
  product.UnitsInStock = Convert.ToInt16(postData["UnitsInStock"]);

  //Sending changes back to repository
  bool success = true;
  try
  {
    _repository.SubmitChanges();
  }
  catch (Exception ex)
  {
    Debug.Write(ex.Message);
    success = false;
  }

  //Returning data - we can hadle this data in form afterSubmit event
  return Json(success);
}

That makes our CRUD scenario complete. Source code can be downloaded from usual location. To make deleting easy, I have changed FK_Order_Details_Products foreing key in Northwind database.

Today we will look at searching in jqGrid. We will focus on native API mechanisms.
There are four searching approaches in jqGrid. We will go through all of them, but first let's prepare some common configuration.
<script type="text/javascript">
  $(document).ready(function() {
    $('#jqgProducts').jqGrid({
      //url from wich data should be requested
      url: '/Home/ProductsGridData/',
      //type of data
      datatype: 'json',
      //url access method type
      mtype: 'POST',
      //columns names
      colNames: ['ProductID', 'ProductName', 'Supplier', 'Category', 'QuantityPerUnit', 'UnitPrice', 'UnitsInStock'],
      //columns model
      colModel: [
                  { name: 'ProductID', index: 'ProductID', align: 'left', search: true, stype: 'text', searchoptions: { sopt: ['eq', 'ne'] } },
                  { name: 'ProductName', index: 'ProductName', align: 'left', search: true, stype: 'text', searchoptions: { sopt: ['eq', 'ne'] } },
                  { name: 'Supplier', index: 'SupplierID', align: 'left', formatter: supplierFormatter, search: true, stype: 'select', edittype: 'select', surl: '/Home/SuppliersSelect', searchoptions: { sopt: ['eq', 'ne']} },
                  { name: 'Category', index: 'CategoryID', align: 'left', search: true, stype: 'select', edittype: 'select', surl: '/Home/CategoriesSelect', searchoptions: { sopt: ['eq', 'ne']} },
                  { name: 'QuantityPerUnit', index: 'QuantityPerUnit', align: 'left', search: false },
                  { name: 'UnitPrice', index: 'UnitPrice', align: 'left', formatter: 'currency', formatoptions: { decimalSeparator: '.', thousandsSeparator: ',', decimalPlaces: 2, prefix: '$'}, search: false },
                  { name: 'UnitsInStock', index: 'UnitsInStock', align: 'left', formatter: unitsInStockFormatter, search: false }
                ],
      //pager for grid
      pager: $('#jqgpProducts'),
      //number of rows per page
      rowNum: 10,
      //initial sorting column
      sortname: 'ProductID',
      //initial sorting direction
      sortorder: 'asc',
      //we want to display total records count
      viewrecords: true
    });
  });
</script>
As you can see, we have extended our colModel definition. We have specified if we can search by column (search parameter) and what is the type of searching field (stype parameter). For 'select' search fields we have provided url from where jqGrid can get actual select markup via ajax request (surl parameter). For simplicity we have also limited possible value operators to 'equal' and 'not equal' (sopt array in searchoptions parameter). You should also notice that we have changed method type from GET to POST. We did it, because the list of parameters which will be sent back to server will vary depending on searching approach and set filters.
Now we should prepare controller actions which returns markup for our 'select' fields:
/// <summary>
///
Provides select markup for suppliers filter
/// </summary>
/// <returns>
select markup</returns>
public ActionResult SuppliersSelect()
{
  Dictionary<int, string> suppliers = new Dictionary<int, string>();
  foreach (Supplier supplier in _repository.GetSuppliers())
    suppliers.Add(supplier.SupplierID, supplier.CompanyName);
  return PartialView("SelectPartial", suppliers);
}

/// <summary>
///
Provides select markup for categories filter
/// </summary>
/// <returns>
select markup</returns>
public ActionResult CategoriesSelect()
{
  Dictionary<int, string> categories = new Dictionary<int, string>();
  foreach (Category category in _repository.GetCategories())
    categories.Add(category.CategoryID, category.CategoryName);
  return PartialView("SelectPartial", categories);
}
SelectPartial.ascx has very simple content:
<select>
  <option value=''></option>
  <% foreach (KeyValuePair<int,string> value in (Dictionary<int, string>)Model) { %>
    <option value='<%= Html.Encode(value.Key.ToString())%>'>
      <%= Html.Encode(value.Value)%>
    </option>
  <% } %>
</select>
When all of the common stuff is done, we can start going through search approaches. Let's start with toolbar searching. When we use this approach, all the inputs elements are created below the header elements. Filter values are passed to application separately for each filter with value definied by user. We turn on this approach like this:
$('#jqgProducts').filterToolbar();
Custom searching creates a search form for the grid (it requires a div placeholder on page). This form can be based on colModel definitions (like in our example), or you can provide filterModel for it. Filter values are passed to application in exactly the same way as for the toolbar searching. Initialization code looks like this:
$('#jqgsProducts').filterGrid('#jqgProducts', { gridModel: true, gridNames: true, formtype: 'vertical', autosearch: false, enableSearch: true, enableClear: true });
Single field searching displays popup where you can choose field to filter, operator which will be applied and filter value. Application always receives three parameters: searchField (name of chosen field), searchOper (operator) and searchString (value). It is displayed with following call:
$('#jqgProducts').searchGrid();
Advanced searching works almost the same as single field searching. The difference is that you can set multiply conditions. Application receives only one parameter (filters) which contains JSON string that needs to be parsed. Display call is also pretty much the same, we only need to add multipleSearch parameter.
$('#jqgProducts').searchGrid({ multipleSearch: true });
Now we need to modify controller action to support postData and filtering. There is one very important note to make. Following code is only for example purposes and should never be used in real application (it has no proper validation, types interpretation etc.).
/// <summary>
///
Provides json data for jqGrid
/// [WARNING: This code is for presentation purposes only, and should never be use in real application, it lacks validation, types interpretation etc.]
/// </summary>
/// <param name="postData">
POST parameters collection</param>
/// <returns>
json data</returns>
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ProductsGridData(FormCollection postData)
{
  //Extracting parameters from collection
  string sortExpression = postData["sidx"];
  string sortDirection = postData["sord"];
  int pageIndex = Convert.ToInt32(postData["page"]);
  int pageSize = Convert.ToInt32(postData["rows"]);

  string filterExpression = String.Empty;
  if (Convert.ToBoolean(postData["_search"]))
  {
    //Preparing filter expression for single field approach
    if (postData.AllKeys.Contains("searchField")
        && postData.AllKeys.Contains("searchString")
        && postData.AllKeys.Contains("searchOper"))
      filterExpression = GetFilter(postData["searchField"],
                         postData["searchOper"].Equals("eq") ? "=" : "!=",
                         postData["searchString"]);
    //Preparing filter expression for advanced approach
    //[WARNING: Quite nasty code ahead, don't do it like this ;)]

    else if (postData.AllKeys.Contains("filters"))
    {
      string groupOperator = " And ";
      if (postData["filters"].Contains("\"groupOp\":\"OR\""))
        groupOperator = " Or ";
      string filtersRules = postData["filters"].Substring(postData["filters"].IndexOf("[") + 2);
      filtersRules = filtersRules.Remove(filtersRules.Length - 3).Replace("},{", "|").Replace("\"", String.Empty);
      foreach (string filterRule in filtersRules.Split('|'))
      {
        Match filterValues = Regex.Match(filterRule, "^field:(.*),op:(.*),data:(.*)$");
        filterExpression = filterExpression + GetFilter(filterValues.Groups[1].Value,
                           filterValues.Groups[2].Value.Equals("eq") ? "=" : "!=",
                           filterValues.Groups[3].Value) + groupOperator;
      }
      filterExpression = filterExpression.Remove(filterExpression.Length - groupOperator.Length);
    }
    //Preparing filter expression for toolbar and custom approach
    else
    {
      foreach (string postDataKey in postData.AllKeys)
      {
        if (!postDataKey.Equals("nd") && !postDataKey.Equals("sidx")
            && !postDataKey.Equals("sord") && !postDataKey.Equals("page")
            && !postDataKey.Equals("rows") && !postDataKey.Equals("_search"))
          filterExpression = filterExpression + GetFilter(postDataKey, "=", postData[postDataKey]) + " And ";
      }
      filterExpression = filterExpression.Remove(filterExpression.Length - 5);
    }
  }

  //Getting total records count from repository
  int totalRecords = _repository.GetProductsCount();

  //Preparing anonymous variable with json data
  var productsData = new
  {
    //total pages count
    total = (int)Math.Ceiling((float)totalRecords / (float)pageSize),
    //page number
    page = pageIndex,
    //total records count
    records = totalRecords,
    //table with rows data
    rows = (from product in _repository.GetProducts(filterExpression, sortExpression, sortDirection, pageIndex - 1, pageSize)
            select new
            {
              //row id
              id = product.ProductID,
              //table of cells values
              cell = new string[] {
                                     product.ProductID.ToString(),
                                     product.ProductName,
                                     "[" + product.Supplier.SupplierID.ToString()
                                     + "] " + product.Supplier.CompanyName,
                                     product.Category.CategoryName,
                                     product.QuantityPerUnit,
                                     product.UnitPrice.ToString(),
                                     product.UnitsInStock.ToString()
                                   }
            }
           ).ToArray()
  };

  //Returning json data
  return Json(productsData);
}

private string GetFilter(string searchField, string searchOper, string searchValue)
{
  if ((searchField == "ProductID") || (searchField == "SupplierID") || (searchField == "CategoryID"))
    return searchField + " " + searchOper + " " + searchValue;

  if ((searchField == "ProductName"))
    return searchField + " " + searchOper + " \"" + searchValue + "\"";

  return String.Empty;
}
Let's take a look at our work result (source code is available here).

Last time we have set up our first jqGrid. In this post I'm going to take a look at columns formatting.
First let's use predefined formatter. Setting any of predefined formats for column is as simple as adding formatting type and options to colModel definition. In our example we will format UnitPrice as USD. To achieve this, we will set formatting type to currency with following options: decimalSeparator: '.', thousandsSeparator: ',', decimalPlaces: 2 and prefix: '$'.
<script type="text/javascript">
  $(document).ready(function() {
    $('#jqgProducts').jqGrid({
      ...
      colModel: [
                  ...
                  { name: 'UnitPrice', index: 'UnitPrice', align: 'left', formatter: 'currency', formatoptions: { decimalSeparator: '.', thousandsSeparator: ',', decimalPlaces: 2, prefix: '$'} },
                  ...
                ],
      ...
    });
  });
</script>

Now let's take a look at custom formatter. We will prepare formatting javascript function for UnitsInStock column (instead of displaying numbers we will be displaying flags which color will depend on amount of units). Function receives three parameters: cellvalue - original value for cell, options - array of options passed in colModel, rowObject - object with row data. Return value of our function should be new value for a cell. We also have to set formatting in colModel.
<script type="text/javascript">
  $(document).ready(function() {
    $('#jqgProducts').jqGrid({
      ...
      colModel: [
                  ...
                  { name: 'UnitPrice', index: 'UnitPrice', align: 'left', formatter: 'currency', formatoptions: { decimalSeparator: '.', thousandsSeparator: ',', decimalPlaces: 2, prefix: '$'} },
                  { name: 'UnitsInStock', index: 'UnitsInStockPrice', align: 'left', formatter: unitsInStockFormatter }
                ],
      ...
    });
  });

  function unitsInStockFormatter(cellvalue, options, rowObject) {
    var cellValueInt = parseInt(cellvalue);
    if (cellValueInt > 10)
      return "<img src='../../Content/images/ui-flag_green.png' alt='" + cellvalue + "' title='" + cellvalue + "' />";
    else if (cellValueInt > 0)
      return "<img src='../../Content/images/ui-flag_blue.png' alt='" + cellvalue + "' title='" + cellvalue + "' />";
    else
      return "<img src='../../Content/images/ui-flag_red.png' alt='" + cellvalue + "' title='" + cellvalue + "' />";
  };
</script>

Let's take it a little bit further. We will format Supplier column so that it will include a link that displays a popup with supplier details. To achieve this we will use jQuery UI Dialog. To do that, we must reference jQuery UI script file.
<head>
  ...
  <script src="/Scripts/jquery-ui-1.7.2.custom.min.js" type="text/javascript">
  </script>
  ...
</head>
In Controller we will prepare method returning supplier details.
/// <summary>
///
Provides json data for supplier popup
/// </summary>
/// <param name="supplierId">
supplier identifier</param>
/// <returns>
json data</returns>
public ActionResult SupplierData(int supplierId)
{
  //Getting supplier from repository
  Supplier supplier = _repository.GetSupplier(supplierId);

  //Preparing anonymous variable with json data
  var supplierData = new
  {
    companyName = supplier.CompanyName,
    address = supplier.Address,
    postalCode = supplier.PostalCode,
    city = supplier.City,
    country = supplier.Country,
    phone = supplier.Phone,
    homePage = supplier.HomePage
  };

  //Returning json data
  return Json(supplierData);
}

We also must add html markup for dialog.
<div id="jqdlgSupplier">
  <span id="sCompanyName"></span><br /><br />
  <span id="sAddress"></span><br />
  <span id="sPostalCode"></span>, <span id="sCity"></span><br />
  <span id="sCountry"></span><br /><br />
  <span id="sPhone"></span><br />
  <span id="sHomePage"></span>
</div>

At the end we will write two new javascript functions (one for cell formatting and one for dialog display) and add some more initialization logic.
<script type="text/javascript">
  $(document).ready(function() {
    $('#jqgProducts').jqGrid({
      ...
      colModel: [
                  ...
                  { name: 'Supplier', index: 'SupplierID', align: 'left', formatter: supplierFormatter },
                  ...
                  { name: 'UnitPrice', index: 'UnitPrice', align: 'left', formatter: 'currency', formatoptions: { decimalSeparator: '.', thousandsSeparator: ',', decimalPlaces: 2, prefix: '$'} },
                  { name: 'UnitsInStock', index: 'UnitsInStockPrice', align: 'left', formatter: unitsInStockFormatter }
                ],
      ...
    });
    $('#jqdlgSupplier').dialog({ autoOpen: false, bgiframe: true, resizable: false, title: 'Supplier' });
  });

  ...

  function supplierFormatter(cellvalue, options, rowObject) {
    return "<a href='' onlick='showSupplierDialog(this, " + cellvalue.substr(1, 1) + "); return false;'>" + cellvalue.substr(4) + "</a>";
  };

  function showSupplierDialog(linkElement, supplierId) {
    //request json data
    $.getJSON('/Home/SupplierData/', { supplierId: supplierId }, function(data) {
      //set values in dialog
      $('#sCompanyName').text(data.companyName);
      $('#sAddress').text(data.address);
      $('#sPostalCode').text(data.postalCode);
      $('#sCity').text(data.city);
      $('#sCountry').text(data.country);
      $('#sPhone').text(data.phone);
      $('#sHomePage').text(data.homePage);
      //get link position
      var linkPosition = $(linkElement).offset();
      //set dialog position
      $('#jqdlgSupplier').dialog('option', 'position', [linkPosition.left, linkPosition.top]);
      //open dialog
      $('#jqdlgSupplier').dialog('open');
    });
  };
</script>

And voila. We can seat and admire our grid.

There is one more thing which needs to be mentioned. If you want custom formatted column to be editable (I'm going to write about CRUD scenario soon), you need to provide unformatter function which will extract original value from cell.
As usual, example source code can be found here.
Older Posts