38
ASP.NET MVC jqGrid – Documentation ( unfinished ) By: Trevor Scharf ([email protected] ) www.kashn.com JqGrid has been growing increasingly popular over the years, but there seemed to be missing something. A cheap/free integration of jqGrid into ASP.NET MVC 3(.NET 4). So I was busy with a web site when I decided to look at my options for displaying data from a grid, and became ever fascinated with jqGrid and decided to build my own server side integration of jqGrid into ASP.NET MVC and Entity Framework. Now this is still under development, and hopefully with time will continue to grow and gain more features, better performance, and of course less bugs. I’m hoping somewhere down the road to expand my database framework support beyond Entity Framework, to a variety of other database frameworks including RavenDB, and possibly create a DB Provider interface down the line where others can plugin and create one themselves if one is not already provided. This assumes you have .NET 4+ and an ASP.NET MVC 3+ Razor website(webforms view engine will still work in a lot of cases where the razor @<text></text> is not used, but is not guaranteed bug-free ). or possibly a hybrid webforms/razor site. This is not built for webforms! To start all you will need is a few javascript and css files loaded in your page. Missing is the jquery ui files which might have different versioning. - jqGrid/css/ui.jqgrid.css - "/Content/jquery.jqGrid-4.3.0/js/i18n/grid.locale-en.js", - "/Content/jquery.jqGrid-4.3.0/js/jquery.jqGrid.src.js" - mvcJqGrid.js Also you should add in the jqGridMVC.css file which is included in the JQGridAdditionalResources folder. This is included in the provided download.

j q Grid Documentation

Embed Size (px)

Citation preview

Page 1: j q Grid Documentation

ASP.NET MVC jqGrid – Documentation ( unfinished ) By: Trevor Scharf ([email protected]) www.kashn.com

JqGrid has been growing increasingly popular over the years, but there seemed to be missing something. A cheap/free integration of jqGrid into ASP.NET MVC 3(.NET 4). So I was busy with a web site when I decided to look at my options for displaying data from a grid, and became ever fascinated with jqGrid and decided to build my own server side integration of jqGrid into ASP.NET MVC and Entity Framework. Now this is still under development, and hopefully with time will continue to grow and gain more features, better performance, and of course less bugs. I’m hoping somewhere down the road to expand my database framework support beyond Entity Framework, to a variety of other database frameworks including RavenDB, and possibly create a DB Provider interface down the line where others can plugin and create one themselves if one is not already provided. This assumes you have .NET 4+ and an ASP.NET MVC 3+ Razor website(webforms view engine will still work in a lot of cases where the razor @<text></text> is not used, but is not guaranteed bug-free). or possibly a hybrid webforms/razor site. This is not built for webforms!

To start all you will need is a few javascript and css files loaded in your page. Missing is the jquery ui files which might have different versioning.

- jqGrid/css/ui.jqgrid.css- "/Content/jquery.jqGrid-4.3.0/js/i18n/grid.locale-en.js",- "/Content/jquery.jqGrid-4.3.0/js/jquery.jqGrid.src.js"

- mvcJqGrid.js

Also you should add in the jqGridMVC.css file which is included in the JQGridAdditionalResources folder. This is included in the provided download.

All but the ‘yellow’ can be downloaded from the jqGrid site. Or you can use the files included in the download package.

Also you will need to add a project reference the jqGrid dll included in the package.

Next, an addition to the web.config will be needed. The namespace ‘JQGrid’ must be added so pages can pick up on the Html extensions.

Page 2: j q Grid Documentation

<pages pageBaseType="System.Web.Mvc.WebViewPage"> <namespaces> <add namespace="System.Web.Helpers" /> <add namespace="System.Web.Mvc" /> <add namespace="System.Web.Mvc.Ajax" /> <add namespace="System.Web.Mvc.Html" /> <add namespace="System.Web.Routing" /> <add namespace="System.Web.WebPages" /> <add namespace="JQGrid" /> </namespaces> </pages>

Setting up the Controller

Setting up the controller is necessary. All that is required is to inherit the controller from GridController<yourDbEntityContext> such as below:

public class KashnController : GridController<KashnEntities>

That is all that is required for the controller to be set up. Now all that is needed is to create the Action that you are calling that will return a page with a grid.

public ActionResult ViewBlogs() { return GridSearch(c => c.BlogEntries /*TABLE. CAN MAKE 'INCLUDE()' statements here*/,c => c/*WHERE.ORDERBY STATEMENTS*/,c => c.Select(be => new { be.BlogEntryId /*id field must be included and be first field */, be.Title, be.PostDate })/*MOLD THE DATA HERE*/); }

@(Html.jqGrid<BlogEntry>("Blogs", s => { /*HOOKUP SETTINGS HERE*/ }))

The Id field is required as the first anonymous property in the third parameter. That is all that is

required. This is a small and easy rule to follow. In this example I call the GridSearch method which returns an ActionResult for the View. On the View Side I call the below and it will pick up on the grid details and securely manage grid searching and ordering. Only the fields specified in the return set can be searched unless otherwise specified in another parameter I will go over later.

Html.jqGrid<*EntityType*>(*Grid Title*,*settings & other methods*);

Page 3: j q Grid Documentation

Now you should have a simple grid as shown below rendered into the view with the *optional* search functionality. The Blog Entry Id search field can be easily hidden and more can be added even if they are down the relationship path of the EntityModel.

But what about encoding?

All columns by default are auto html encoded for security reasons. If you put “<b>HELLO<b>” it will come out that way on the column. Luckily there is a feature to bypass this.

return GridSearch(c => c.BlogEntries,c => c,c => c.Select(be => new { be.BlogEntryId, Title = NoEncode(be.Title), be.PostDate }));

“NoEncode(*object*)” will tell the column data provider to skip encoding the column if need be.

Dude…I need a custom column with buttons and such!

Easy as 1 + 1. Just add another property/properties to the third parameter’s object as below.

return GridSearch(c => c.BlogEntries,c => c,c => c.Select(be => new { be.BlogEntryId, Title = NoEncode(be.Title), be.PostDate, Actions = NoEncode("<a href='/Blog/DoSomething' >Do Something</a>&nbsp;&nbsp;<a href='AndAnother'>And Another</a>") }));

Page 4: j q Grid Documentation

Good...but that actually looks yucky with the html like that. Lets clean that up a bit with a few shortcut methods called Link(*Url*,*Text*,*Boolean[should this show]*) and Space(*number of &nbsp;s*)

return GridSearch(c => c.BlogEntries,c => c,c => c.Select(be => new { be.BlogEntryId, Title = NoEncode(be.Title), be.PostDate, Actions = NoEncode(Link("/Blog/DoSomething","Do Something") + Space(2) + Link("/Blog/AndAnother","And Another")) }));

Wow that looks a lot better. The Link() method even has a third parameter that accepts a Boolean to judge whether it should show or not, so none of those inline ‘x ? a : b’ statements are needed. You could actually use the below also. Notice the ‘$’. I picks up the current controllers name. So don’t use this with a link that points to another controller.

Link("$DoSomething","Do Something")

So, I have search already provided…but I still want to filter this data further…

The second parameter can handle filtering for the construction of the generated query that gets sent to the database. Just use it like you would handle ‘Where()’ statements for any entity framework query.

var tenDaysAgo = DateTime.Now.AddDays(-10); return GridSearch(c => c.BlogEntries,

c => c.Where(entry => entry.PostDate >= tenDaysAgo ),

c => c.Select(be => new { be.BlogEntryId, Title = NoEncode(be.Title), be.PostDate }));

Above I am doing some extra filtering. I’m telling it to find all blog entries within the past 10 days.

Wow. This grid looks too big, maybe too small. Lets give it some dimensions that feel Just Right

Page 5: j q Grid Documentation

Alright, now we are getting into modifying the grid itself. This will be taking place on the View itself.

@(Html.jqGrid<BlogEntry>("Blogs", settings => { settings.GridWidth(500); settings.GridHeight("300px");}))

As you can see, the Grid Width and Grid Height is editable in their own manner. But I still need control over how many rows are pulled….

@(Html.jqGrid<BlogEntry>("Blogs",5, settings => { settings.GridWidth(500); settings.GridHeight("300px");}))

As you can see, the method has an overload that has a 2nd parameter that accepts the number of rows per page.

Rows & Column Styling

As we all know, columns should be able to have custom widths. This is very easy. There are multiple approaches to this as seen below:

settings.ColWidths("Title,PostDate", 300, 80);

The ColWidths method allows to quickly set the widths of many columns. settings.columns.Title.width = 300; settings.columns.PostDate.width = 80;

The method above accesses a dynamic property on the settings called ‘columns’. From this you can access each column dynamically. The values placed on the columns here will get serialized and added to the default properties that are part of the javascript object used for the column in the grid generation. So any column/colModel property available from the jqGrid javascript api (http://www.trirand.com/jqgridwiki/doku.php?id=wiki:colmodel_options)

settings.FindCol("Title").Width = 300; settings.FindCol("PostDate").Width = 300;

The FindCol Method acceses the underling ViewGridColumn object which has quite a view properties of its own which I will dig deeper into further on.

Columns can be styled quickly through multiple available ways as shown below:

settings.FindCol("Title").Style("color:blue;padding:8px;");

Page 6: j q Grid Documentation

settings.ColStyle("Title,PostDate", "color:blue;padding:8px");

Rows can also be styled through a couple powerful manners as discussed below:

settings.RowCss(new { background = "yellow" });

settings.RowCss(new { background = "blue", color = "white" }, Browser.IE7_8); settings.RowCss(new { background = "yellow" },Browser.NotIE);

Filters style by value in column of grid.

settings.FilterRowStyle("Title", "JQGrid MVC Part 1 of Blog Series", new { background = "green" });

Column Headers

Column headers can easily be changed. The method of approaching this is show below:

settings.FindCol("PostDate").FriendlyName = "Date of Post";

or

settings.FriendlyName("PastDate", "Date of Post");

Hiding a Column

If you need to hide a column just use the hide method as show below.

settings.Hide("BlogId,PostDate");

Turning off Search Textbox Auto Creation

settings.TurnOffSearch(); or settings._ConstructSearch = false;

Hiding the Print Button

settings.printHidden = true;

Page 7: j q Grid Documentation

Pulling Filtered Column Data From The Database

The third parameter is already accessing the filtered result set after it was returned by the database, and the second parameter doesn’t allow a Select() method in it with the traditional ‘GridSearch’ function. The normal GridSearch method maintains all the methods and paths from the Entity, but we will be pulling down an anonymous object so those useful methods will be dropped. So that way to control the pulled columns is to do the below method using ‘SelectiveGridSearch’:

var tenDaysAgo = DateTime.Now.AddDays(-10);

return SelectiveGridSearch(c => c.BlogEntries,c => c.Where(entry => entry.PostDate >= tenDaysAgo).Select(be => new { be.BlogEntryId,be.Title}), set => set.Select(be => new { be.BlogEntryId, be.Title, Actions = NoEncode("Actions") }));

This is very useful for only pulling very selective data from the database without loading everything into memory. If a column had an Image or Document stored in a column in binary, sometimes it would be better to ignore these columns and others that aren’t being pulled.

Hookup Searching Down Relational Object Paths

The fourth parameter accepts a paths string that will allow search down a relationship path. So if you need to search Blog Entries created by a certain user with a First Name and Last Name provided you can use the string "User.FirstName,User.LastName. Now those properties will be searchable down the relationship path.

return GridSearch(c => c.BlogEntries.Include("User"),c => c.Where(entry => entry.PostDate >= tenDaysAgo), set => set.Select(be => new { be.BlogEntryId, be.Title, Actions = NoEncode("Actions") }),"User.FirstName,User.LastName");

To create the actual search textboxes on the other side you can use the following:

settings.RelationalTextBox("First Name", "FirstName"); settings.RelationalTextBox("Last Name", "LastName");

Page 8: j q Grid Documentation

Or manually use a textbox with a name of “search$FirstName” and “search$LastName” if you prefer to build them manually. You can append these manually built fields by doing things such as :

settings.AppendHtml("Last Name: <input type='text' name='search$LastName' />");

settings.PrependHtml("Last Name: <input type='text' name='search$LastName />");

These will be inserted into the search form. There are ways to build the search form completely manually and invoke searching on the grid but that is a more advanced topic that will be discussed later on.

Creating another grid on the page from another Action

Creating another grid from another action on a controller is easy.The below required a 2nd Generic parameter accepting the controller type of the controller being invoked. The third parameter accepts that Action with its default parameters to be initially called. The fourth parameter is the url to be called. I set settings._ConstructSearch to ‘true’ here because by default the search isn’t created because these grids will be primarily constructed as subgrids within another grid and therefore the search is not by default created.

@(Html.jqGrid<BlogEntry, BlogController>("Blog Entries", settings => { settings._ConstructSearch = true; }, b => b.ViewBlogs(), "/Blog/ViewBlogs"))

Returning a SubGrid

Below I create an action on the controller called ‘ViewUsers’. This returns the users in the system. But lets just say I want the subgrid that is expanded using the ‘plus’ icon on the far left of the grid to view the users blog entries. I create another method that accepts a parameter name of ‘id’. This is the name of the rowid sent during an ajax call. This returns a normal GridSearch. On the view I create the normal Html.jqGrid. One difference is the call to PageableSubGrid on the settings object. Inside this I call Html.jqSubGrid which works almost exactly like the normal jqGrid method except is handled as a subgrid. Subgrids can have subgrids of their own. These methods of course require the two generic parameters and the lamba method expression on the controller as seen in con => con.ViewUserBlogEntries(-1)”.

-------------CONTROLLER------------------------------------------------------------------

public ActionResult ViewUsers() {

Page 9: j q Grid Documentation

return GridSearch(c => c.Users, c => c, bes => bes.Select(b => new {b.UserId, b.FirstName, b.LastName })); }

Continued on next page…

public ActionResult ViewUserBlogEntries(int id = 0) { return GridSearch(c => c.BlogEntries.Include("User"), c => c.Where(be => be.User.UserId == id), c => c.Select(be => new { be.BlogEntryId, be.Title, Actions = NoEncode("Actions") })); }

--------VIEW-----------------------------------------------------------------------------

@(Html.jqGrid<User>("Users",settings => { settings.PageableSubGrid( Html.jqSubGrid<User, BlogController>("UserBlogs", s => { }, con => con.ViewUserBlogEntries(-1), "/Blog/ViewUserBlogEntries"));

}))

Creating a expandable Templated SubContent for rows. This accepts either a string or a @<text></text> format. This requires jquery template to be referenced. If you know anything about jquery tmpl then it should be easy to figure out. If not, search it up and download jquery tmpl( http://api.jquery.com/jquery.tmpl/ )

settings.SubContent(@<text> <div> Hello ${FirstName} ${LastName} <h1>Very Cool</h1> </div> </text>);

Deep Dive into the @<text> razor feature.

I want to go over the @<text> syntax for a moment that razor supports. You may or may not know, but underneath it creates an Func<object,HelperResult>. I actually retrieve the inner text in-between content.Invoke(new { }).ToString() where ‘content’ is the Func<object,HelperResult> object. I think this is very good to know. I know I’m diverting

Page 10: j q Grid Documentation

from the subject but I think it’s important. It can be used to create a buffer function as below which can be retrieve later so as to avoid messy string concatenation.

public static string Buffer(this System.Web.Mvc.WebViewPage<dynamic> page, string key, Func<object,HelperResult> content) { page.Response.Flush(); page.ViewData[key] = content.Invoke(new { }).ToString(); return ""; }

Capturing the Row Selected Event

Below is an example of reacting to a row being selected. There are two values to capture here. First of all the variable ‘val’ is the object relating to the row so you can access all the column values passed in. This is retrieved and added as an addition to the already available parameters already provided by jqGrid. There is also an ‘rowid’ field relating to the id key of the row.

settings.OnRowSelect("alert(val.Title);");

Below is a description from the jqGrid Wiki site:

onSelectRow(rowid,status){

}

Raised immediately after row was clicked. rowid is the id of the row,status is the status of the selection. Can be used when multiselect is set to true. true if the row is selected, false if the row is deselected.

Capturing the GridComplete Event

s.OnGridComplete("alert('Grid Complete');");

gridComplete(){

}

Description from the jqGrid Wiki site:

“This fires after all the data is loaded into the grid and all other processes are complete. Also the event fires independent from the datatype parameter and after sorting paging and etc.”

Page 11: j q Grid Documentation

Capturing the LoadComplete Event

settings.OnLoadComplete("alert('Grid Loaded');");

loadComplete(data){

}

Load complete is executed after every server request for data. The ‘data’ variable hold the data passed into each response depending on the datatype grid parameter.

Implementing an Event and/or function not already implemented by ASP.NET MVC jqGrid

To do this you must call on the dynamic functions object. From there just extend it with the name of the desired event/method and set it to the function itself as seen below.

settings.functions.ondblClickRow = "function(rowid, iRow, iCol,e) { …Do Something… }";

For more information regarding events go to

http://www.trirand.com/jqgridwiki/doku.php?id=wiki:events

Hiding a Column From the Controller End

To avoid generating a column on the other end but still have the value available for access use the ‘Hidden’ method.

public ActionResult ViewBlogs() { return GridSearch(c => c.BlogEntries.Include("User"),c => c, set => set.Select(be => new { be.BlogEntryId, Title = Hidden(be.Title), Actions = NoEncode("Actions") }),"User.FirstName,User.LastName");

}

Page 12: j q Grid Documentation

I have a date field, but I want to search for it between a range of dates.

Use the ConvertToDateRange method which accepts the name of the column.

settings.ConvertToDateRange("PostDate");

This will hook up the entire underlying entity framework searching for between date ranges.

I want to group by a column value

settings.GroupBy("PostDate",true);

settings.GroupSummaryByField("PostDate", GroupSummaryType.count, "Total Number of Entries On Date: {0}");

To group by just provide the first parameter in the GroupBy method with the name of the field. Here I group by the date. The second parameter judges whether a group summary will be shown. If you wish to use the Group Summary use the GroupSummaryByField method in addition with the name of the field with the summary, the GroupSummaryType(all shown below) and the string formatter template where the {0} will be replaced by the summary types value.

From the above you can see that the third property allows you to change the group text and the fourth allows you to control whether or not to show the summary when the group is collapsed. public enum GroupSummaryType { sum, count, avg, min, max }

As you can see there is a multitude of available options. You can find the “sum,cound,avg,min,max” of that column’s values for all items in the group.

You can use a Group Summary for each independent field as necessary.

Page 13: j q Grid Documentation

Editing Inline with the grid

Setting up inline editing is very easy. To start just create the attribute “EditableColumns” on the Action providing the grid. You will need to provide the “IdField” name. The “Table Name”, and an “UpdateString”. The #{x} is converted into the appropriate @ sql parameters . If a column in the #{} is not provided ,that column cannot be updated in the transaction. Next you can use the CommandField method which accepts two parameters. The first is the html which will trigger the edit mode,save,or cancel. If Edit mode is on, the cancel and save commands will hide and vice versa. [EditableColumns(IdField="BlogEntryId",Table="BlogEntries",UpdateString="Title=#{Title},PostDate=#{PostDate}")] public ActionResult ViewBlogs() { return GridSearch(c => c.BlogEntries.Include("User"),c => c, set => set.Select(be => new { be.BlogEntryId, Title = be.Title, be.PostDate, Actions = NoEncode(CommandField("<b>Edit</b>",JQCommand.Edit) + " " + CommandField("<b>Cancel</b>",JQCommand.Cancel) + " " + CommandField("<b>Save Changes</b>",JQCommand.SaveChanges)), }),"User.FirstName,User.LastName"); }

Using a dropdown in edit mode

To use a dropdown in edit mode you just call “AsDropdown” on the settings in the view and pass in the name of the column, and a new Dictionary<string, string> which accepts a key (the id) and the value(the text shown).settings.AsDropdown("PostDate", new Dictionary<string, string>(){ {"5/24/2011","5/24/2011"}, {"5/26/2011","5/26/2011"}, {"5/28/2011","5/28/2011"}, {"11/4/2011","11/4/2011"}

Page 14: j q Grid Documentation

});

Also another way to do this is to do the following:

settings.AsDropdown<KashnEntities>("Title", "Title","Title", c => c.BlogEntries);

This method AsDropdown accepts 4 parameters. The edit-column. The key name, the value name and then the lamba using the ObjectContext type provided to pull from the database in a quick manner.

Using a datepicker

By default, all date column field are hooked up by default with a datepicker, so there is no need to worry of thise.

Further Control of Editing Types Per Column

settings.InputEditType("IsVisible", EditType.checkbox);

public enum EditType { text, textarea,select,checkbox, password, button, image, file }

Creating a Delete Button on a Column

Use the command field method with the JQCommand.Delete enum.

CommandField("<b>Delete</b>",JQCommand.Delete)

On the action in the controller itself use the attribute DeletableRow as shown below.

[DeletableRow(Table="BlogEntries",IdFeild="BlogEntryId")]

If you need any more customizability like role checking,ect. you can just create another separate method on the controller and a link in a column that points to it. This is just available for rapid development and ease of use.

Page 15: j q Grid Documentation

Creating Inline Search Toolbar

Call SearchToolbar containing a comma separated list of the column being searched.

settings.SearchToolbar("Title,PostDate");

Need an inline search dropdown used for searching? Use the follow which accepts the following arguments: ‘Column,Key,Value,Collection From EntityContext’ and two generic arguments which are the type of EntityContext and the typeof of objects contained within the return collection.

settings.InlineSearchDropdown<KashnEntities, BlogEntry>("Title", "Title", "Title", c => c.BlogEntries);

Creating Custom Search Forms

Creating your own manual form for searching is easy. An easy example is shown below.All you need is for each field to start like ‘FieldName_search’. And if it is a relational property as in the User.FirstName in this example then you use ‘search$FieldName’. For the button that triggers the search I used the GridSearchClick method it has two overloads:

public static HtmlString GridSearchClick(string url, string gridName)

and public static HtmlString GridSearchClick(string gridName)

I use the 2nd since this is posting to the same page for the searching process.The GridSearchClick method generates a onclick event handler so it will be something like onclick=”gridReload(…)”.

<div> <p class="label">First Name: </p> <input type="text" name="search$FirstName" />

Page 16: j q Grid Documentation

<p class="label">Title: </p> <input type="text" name="Title_search" /> <p class="label">Post Date: </p> <input type="text" name="PostDate_search" class="datepicker" /> <input type="button" @jQGrid.GridSearchClick("Blog Entries") value="Search Blogs" /></div>

For :

public ActionResult ViewBlogs() { return GridSearch(c => c.BlogEntries.Include("User"),c => c, set => set.Select(be => new { be.BlogEntryId, Title = be.Title, be.PostDate, Actions = NoEncode(CommandField("<b>Edit</b>",JQCommand.Edit) + " " + CommandField("<b>Cancel</b>",JQCommand.Cancel) + " " + CommandField("<b>Save Changes</b>",JQCommand.SaveChanges) + " " + CommandField("<b>Delete</b>",JQCommand.Delete)), }),"User.FirstName,User.LastName"); }

Page 17: j q Grid Documentation

Now of course arises the question of if two fields have the name ‘XX_search’ that might be for different grids. A way around this is to use the data-gridForm attribute on your container of the search fields. This will scope all internal searches for the input fields to only inputs within that container.

<div data-gridForm="Blog Entries"> <p class="label">First Name: </p> <input type="text" name="search$FirstName" /> <input type="button" @jQGrid.GridSearchClick("Blog Entries") value="Search Blogs" /></div>

Setting Default rules and Values ( possibly from query strings? )

settings.InitialSearchValue("ListPrice", Request["sprice"], "ge"); settings.InitialSearchValue("ListPrice", Request["eprice"], "le");

Building Advanced Search Forms

Sometimes you need more power over your search forms. You might say something to the extend of WHERE (CategoryId = 1 OR CATEGORYId = 2) OR (ProductName LIKE ‘%Red%’ AND ProductName LIKE ‘%Ma%’). You can keep going down the binary tree with ORs and ANDs. Below is an example. The data-groupQuery=’GRIDNAME’ says this will be a group that will be separated by ‘AND’ or ‘OR’ based on the data-gridBoolean attribute. In this case the top level one is ‘AND’. There can be inner groups within each group going down in a chain. In this case We search like this : WHERE ProductName LIKE ‘%xxx%’ AND (ProductCategoryID = x OR ProductCategoryID = y OR ….) AND (ListPrice ……). It give a great flexibility to the querying process without having to build all the query expressions manually to the entity framework. Underneath this creates a chain of LINQ Expression trees that get sent to the Entity Framework.

<div data-groupQuery="Products" data-gridBoolean="AND" > <p class="label">Product Name</p> <input type="text" name="Name_search" /> <p class="label">Category: </p> <div style="overflow:scroll;height:400px;" data-groupQuery="Products" data-gridBoolean="OR" > @foreach(var cat in categories){ <input type="checkbox" name="ProductCategoryID_search" data-value="@cat.ProductCategoryID" />@cat.Name <br /> } </div> <div data-groupQuery="Products" data-gridBoolean="AND"> <p class="label">List Price: </p> <p>Between</p>

Page 18: j q Grid Documentation

<input type="text" name="FromNumber$ListPrice_search" /> <p>and</p> <input type="text" name="ToNumber$ListPrice_search" /> </div> <div @jQGrid.GridSearchClick("Products") class="jqfilter-button" style="text-align:center;width:130px;padding:12px;font-size:16px;margin:8px;float:right;"> Search Products </div> </div>

Settings Up Custom Fields To Be Intercepted

Not technically you can still use the ‘x_search’ format but I’ve built it to take Custom$FieldName as a format to help separate it from any property names that may be on the model itself.

To find you fields value for “Custom$IncludeColor” use:

var rule = JQFilterHandler.CustomRule("IncludeColor"); return GridSearch(e => e.Products.Include("ProductCategory"), e => e.Where(p => rule != null ? p.Name.Contains(rule.data) : true), set => set.Select(p => new { p.ProductID, p.Name, p.ListPrice, p.ModifiedDate }));

Creating a action to be taken pregrid construction of all grids on the site

If you wish to intercept the construction of the grid you can add a handler to the event called PreGridConstruction as seen below. The GridSettings property is handled as a dynamic since the generic cannot be determined at application start.

protected void Application_Start() { jQGrid.PreGridConstruction += (o, args) => { args.GridSettings.RowCss(new { background = "Blue", color = "white" }); args.GridSettings.HideTitlebar(); args.GridSettings.HideColumnHeaders(); }; }

Creating a action to be taken after the view settings have been constructed in the View itself.

Page 19: j q Grid Documentation

protected void Application_Start() { jQGrid.PostGridConstruction += (o, args) => {

}; }

How to add filter-icon functionality to columns

Adding the column icons to the column headers is as easy as below using the method FiltersOnColumns/FilterOnColumns. This can be more useful at times and UI friendly than the default jqGrid search filter functionality.

settings.FiltersOnColumns(); /* or (include columns)*/

settings.FilterOnColumns("Name,ListPrice"); /* or (exclude columns) */ settings.FilterOnColumns("ModifiedDate",true /*Marks As Excluded Column For Filters */)

Page 20: j q Grid Documentation

Creating A Row Template@(Html.jqGrid<Product>("Products",settings => {

settings.RowTemplate(@<text> <div> <table style="border:0px;width:100%;"><tr style="width:100%;"><td style="border:none;"> <img src="${ImageUrl}" style="max-width:160px;maxheight:160px;" /> </td><td> <p>Product Name: ${Name}</p> <p>List Price ${ListPrice}</p> </td></tr></table> </div> </text>);}))

Page 21: j q Grid Documentation

To change it to use the template in two columns use the 2nd parameter overload with a ‘2’, though the better method is to use the floating tiles method, which is described next.

A better way to handle the Two Column/Multiple column situation is to use the FloatingTiles method as seen below. All of the tiles generated are wrapped in a div with float:left and a class of “jqGrid-stackCell”.

settings.FloatingTiles(@<text> <div class='round-8 shadow product-tile' style='background:white;width:460px;margin:7px;'> <div > <table ><tr><td style="border:none;"> <img src="${ImageUrl}" style='border:1px solid silver;' /> </td><td style="border:none;"> <h1 style="font-size:18px;padding-left:0px;margin-left:0px;">${Name}</h1> <p><b>List Price</b>: ${ListPrice}</p> <div class="jqfilter-button-clear tile-button">View Product</div>

Page 22: j q Grid Documentation

<div class="jqfilter-button tile-button">Add to Cart</div> </td></tr></table> </div> </div> </text>);

How to intercept the queries that are created and executed

Below is an example used in the global.asax Application_Start method. You can create events to occur before a search is constructed from the fields sent across and after the query is finished being created. There is a PreSearchConstruction event and a PostSearchConstruction event. If you wish to modify the query return the modified query which is accessed from the EventsArgs. The type of Table is also provided in the EventArgs. If you wish to not modify it return null. As you see here I tell it to filter the BlogEntries by those that don’t have ‘One’ in their titles.

EntityFrameworkQueryFactory.PreSearchConstruction += (o,args) => {

Page 23: j q Grid Documentation

if (args.TableType == typeof(BlogEntry)) { return args.Query.Cast<BlogEntry>().Where(b => !b.Title.Contains("One")); } return null; }; QueryExtensions.PostSearchConstruction += (o, args) => { return null; };

OR

EntityFrameworkQueryFactory.QueryFilterByTable<BlogEntry>(a => { return a.Where(b => !b.Title.Contains("One")); });

Building a custom header barTo create a custom header bar just use the CreateHeader method.

settings.CreateHeader(@<text> <div class="Silver-Gradient" style="height:32px;width:100%;"> <table><tr><td> <p style="line-height:32px;padding-left:14px;">Currently View <b>'@settings._gridName.Replace('-',' ')'</b></p></td></tr></table> </div> </text>);

Creating a Global Header Template

Use the HeaderTemplate method on GridSettings in the global.asax in a the PreGridConstruction event.

args.GridSettings.HeaderTemplate(@" <div class='Silver-Gradient' style='height:32px;width:100%;padding-top:4px;padding-bottom:4px;'> <table style='width:97%;'><tr style='width:100%;'><td align='left'>

<p style='line-height:32px;padding-left:14px;'>Currently Viewing <b>'" + args.GridSettings._gridName.Replace('-',' ') + @"'</b></p></td>< <td>${Placeholder}</tr></table>

Page 24: j q Grid Documentation

</div> ");

This will automatically apply across the board. If you use the CreateHeader() method on the view it will override this. Also if you want to inject content into the headerTemplate you can use the method AddToHeaderTemplate. This will replace the ${PlaceHolder} piece you input into the template.

settings.AddToHeaderTemplate(@<text> <p>Some Content</p> </text>);

Creating a Column Drop boxTo create a column drop box just create a container within the custom header or wherever with the class of dropbox like in this example.

<div style="width:600px;height:28px;border:1px solid #E6E6E6;float:right;margin-left:15px;" class="capture-box" > <div class="capture-box-tag" style="line-height:28px;"><p>&nbsp;Drag columns here to hide them</p></div> </div>

<div style="width:600px;height:28px;border:1px solid #E6E6E6;float:right;margin-left:15px;" class="capture-box" > <div class="capture-box-tag" style="line-height:28px;"><p style="color:Gray;"> <div class="captured-item-template"> <b> ${column} </b> </div> &nbsp;Drag columns here to hide them</p></div> </div>

The capture-box-tag is there when there are no columns in it. The captured-item-template container is a template for how the column name should be displayed in the box. Each item will have the captured-item class on it so you can style them. You just drag over a column to it and it will be added to the box and the column will be hidden. When you click the name it will show the column and disappear from the box. See the example picture below. These styles of course can be customized to the choosing using the classes provided that you can inspect through firebug. Currently there is a small bug with the inline searching where they disappear but will be resolved soon.

Page 25: j q Grid Documentation

If you want to change the style of the capture box when hover over with a column being dragged just add a style in the stylesheet for .capture-box-hover. That is triggered when dragging a column into the capture box.

Starting columns out in the capture box

settings.MoveFieldsToCaptureBox("FirstName", "LastName");

Pushing data from one grid to another/Syncing Grids

settings.PushToGrid("User Blogs", "UserId");

Let’s say I create this on a grid for listing users and I want it so when a row is selected that another grid on the page called ‘User Blogs’ to update to show the user’s blogs. The PushToGrid method takes two arguments, the name of the other grid and the field that will be used to filter the other grid down further. In this case every time User Blogs makes a call for data it will pass a parameter in the request called ‘UserId’ containing the id of the user that was selected in the other grid making it an easy way to keep them in sync.

Binding a selected rows values to specific text elements on a page.

settings.BindRowColumnText("UserName", "#lblUserName");

Every time a row is selected its column value for UserName of that row will be bound to the element with an id of lblUserName.

Deeper control of Searchable Fields.

Page 26: j q Grid Documentation

If you need deep control and a stronger guarantee your field won’t be searchable you can use the SearchableColumnsAttribute on the action. This provided a black or white list approach. Either you mark those that are to be searched or those that cannot be searched as so.

[SearchableColumns(Include="BlogEntryId,Title,PostDate")]

[SearchableColumns(Exclude="MySecretField")]

Let’s say that there is a relational property being loaded that you want searchable but has the same property name such as ‘Name’ that already exists on the Primary table being loaded. You might say new { Category = ProductCategory.Name }. Now this will work properly in creating your own search fields because you have control to tell it the field name and that it’s a property down the object path. But JqGrid’s own search form it constructs won’t know this at all. So the way to reroute this issue is to add an the SearchableColumns attribute with the ReroutablePaths property set. This one says that the rule field Category is related to the ProductCategory.Name field and the CategoryModifiedDate is tied to ProductCategory.Modified date and should be bound as so.

[SearchableColumns(ReroutablePaths="Category=ProductCategory.Name;CategoryModifiedDate=ProductCategory.ModifiedDate")]

Advanced Usage Scenarios

Using KnockoutJs & Jquery Tmpl & JqGrid Together

KnockoutJs has been getting a lot of attention lately. Especially as a MVVM javascript implementation developed by Steven Sanderson. If you wish to read up on it there is fantastic documentation and examples at http://knockoutjs.com/ or even Steven Sanderson’s personal webpage http://blog.stevensanderson.com/. KnockoutJs and the most recent Jquery Tmpl is required to use the below. Using the ConstructModel method we create the name of the model. Then we can bind the values we jsonify as hidden columns passed down to jqGrid as Knockouts observableArray properties. These properties will stay in sync at all times with the selected row values.

settings.ConstructModel("CModel", model => { model.Array("BlogEntries"); model.Array("Uploads"); });

To create a bound selected row’s column value to a certain element you can just use:

Page 27: j q Grid Documentation

s.BindRowColumnText("Title", "#Title"); s.BindRowColumnText("Content", "#Content");

And in javascript after any extra hookups have been created on the model call the below in the $(document).ready();

ko.applyBindings(CModel);

To show the bound information use the below or any other javascript template supported by KnockoutJs.

<!-- ko if: Uploads --> <table style="width: 100%;" class="date-table" data-bind="foreach:Uploads"> <tr style="width: 100%;"> <td data-bind="text:FileName"> </td> <td> <a href="#" data-bind="attr: { href: '/ /DownloadDocument?documentId=' + DocumentId }">Download</a> </td> </tr> </table> <!-- /ko -->

Below is a piece pulled out of the jqgrid wiki describing the operators used.

This option is used only in advanced single field searching and determines the operation that is applied

to the element. If not set all the available options will be used. All available option are: 

['eq','ne','lt','le','gt','ge','bw','bn','in','ni','ew','en','cn','nc'] 

The corresponding texts are in language file and mean the following: 

['equal','not equal', 'less', 'less or equal','greater','greater or equal', 'begins with','does not begin with','is

in','is not in','ends with','does not end with','contains','does not contain'] 

Note that the elements in sopt array can be mixed in any order.

****WARNING : IN EARLY TESTING/DEVELOPMENT ( Functional In Most Cases )****

Adding an Add Row Functionality

To an the Add Row functionality just at the ‘Insertable’ attribute with the columns listed and the table. You can use the normal column name, or column:Session[key], or column:Default[defaultValue]. After this there will be an add button created on the grid.

[Insertable(Columns="Title,PostDate,UserId:Session[UserId],Content:Default[None]",Table="BlogEntries")]

Page 28: j q Grid Documentation

Need More Control Over Insert Statement?All you need to do is set the InsertString as seen below!

[Insertable(Table="BlogEntries",Columns="Title,PostDate,UserId:Session[UserId],Content",InsertString="@Title,@PostDate,@UserId,COALESCE(@Content,'X')")]

Using All In One Crud Attribute

[CrudRow( Table="BlogEntries", IdField="BlogEntryId", UpdateString="Title=#{Title},PostDate=#{PostDate}", Deletable = true, InsertColumns = "Title,PostDate,UserId:Session[UserId],Content:Default['None']")]

Want to create a custom Insert String Action like the above :Session[key] and :Default[‘None’]? This can be done by creating an UpdateString Resolver as seen in the session example below:

public class SessionUpdateStringResolver : UpdateStringResolver { public override bool IsMatch(string key) {

Page 29: j q Grid Documentation

Regex reg = new Regex(":Session\\[(?<key>[^']+)\\]"); return reg.IsMatch(key); } public override object Resolve(string key) { Regex reg = new Regex(":Session\\[(?<key>[^']+)\\]"); return HttpContext.Current.Session[reg.Match(key).Groups["key"].Value]; } }

And register the resolver call as seen below in the Application_Start:

UpdateStringResolverRepository.Resolvers.Add(new SessionUpdateStringResolver());

Adding a button to the navigator bar

The method below can be used from settings to add a button to the navigator. More more information regarding custom buttons visit the jqgrid wiki for their great explanation.http://www.trirand.com/jqgridwiki/doku.php?id=wiki:custom_buttons

public void AddButton(string caption = "", string buttonIcon = "", string position = "", string title = "", string id = "", string onClick = "")

Changing To Load Once From Server For Performance Gains

settings.ChangeLoadType(GridLoadType.LoadOnceFromServer);

Page 30: j q Grid Documentation

Handling Settings/Query Execution Control in the Controller

Passing extra control over to the controller is very easy. To Do so all you need to do is create a JQGridPreSearchSettings object which when setup can be passed in to the GridSearch/SelectiveGridSearch methods. This is useful for plugging into the query pipeline, and grid construction for your own custom needs that can be setup with ease outside the controller and can be great for extending the functionality of the plugin for the web developer for extension builders.

JQGridPreSearchSettings jqp = new JQGridPreSearchSettings();

There are two ways for GridConstruction control from the controller. These methods are ‘PostGridConstruction’ and ‘PreGridConstruction’.

jqp.PostGridConstruction.Add((o, e) => { e.GridSettings.global["thisIsCustom"] = "customSetting"; e.GridSettings.columns.ProductID.hidden = false; });

There are two way for GridSearchQuery Control control from the controller. These methods are ‘PostGridQuery and ‘PreGridQuery’.

settings.PreGridQuery.Add((o,e) => { return e.Query.Cast<Product>().Where(p => p.ListPrice > 50); });

/* or */

settings.PreQueryByTable<Product>(p => p.ListPrice > 50);

After Setting up the JQGridPreSearchSettings object pass it in as the last parameter in the GridSearch(or equivalent) method.

return GridSearch(e => e.Products.Include("ProductCategory"), e => e, set => set.Select(p => new { p.ProductID, p.Name, p.ListPrice, p.ModifiedDate, Category = p.ProductCategory.Name, CategoryModifiedDate = p.ProductCategory.ModifiedDate }), .....,jqp);

Page 31: j q Grid Documentation

*****************************************************************************

More documentation to come…Including tabbed sub content & more

Future Features

Export Grid Data as Pdf/Excel Better Printing Support Including Templating JqGrid Data using Jquery Tmpl into a manageable

print structure. Navigator Customizability Tree Grid Support