Currently the API for custom sorting in jqGrid is not very developed. Lucky though, with the jQuery ASP.Net MVC Controls API, it is much simpler to implement custom sorts and multiple column sorts.

There are two ways you can implement this:
1) Custom sort orders on one column on the client side via the jqGrid API. This requires all the data be client side.
2) Sorting the data server side before passing it to the grid.

First Method:

First make your data local. To do this, you have to pass the data into a variable in the ViewData array. This is done on the controller that returns the view.

 public ActionResult Index()
        {

            IEnumerable<Member> memberEntities = _membersServices.GetAllMembers();
            IEnumerable<MemberModel> members = _presentationMapper.Map<IEnumerable<Member>, IEnumerable<MemberModel>>(memberEntities);

            MembersViewModel membersViewModel = new MembersViewModel() { Members = members };
            ViewData["GridDataSource"] = members;
            return View(membersViewModel);
        }

Then you need to define your sort function. You can do it by hand:

StringBuilder sortFunction = new StringBuilder();
    sortFunction.AppendLine("sorttype:");
    sortFunction.AppendLine("function(cellValue, rowObject)");
    sortFunction.AppendLine("{");
    sortFunction.AppendLine("if (cellValue=='RankHighest') return 0;");
    sortFunction.AppendLine("if (cellValue=='RankMiddle') return 1;");
    sortFunction.AppendLine("if (cellValue=='RankLowest') return 2;");
    sortFunction.AppendLine("return 4;");
    sortFunction.AppendLine("}");

Or if you have a sort order in your data already, you can include it in griddata and use it to sort, in my case, RankID:

    StringBuilder sortFunction = new StringBuilder();
    sortFunction.AppendLine("sorttype:");
    sortFunction.AppendLine("function(cellValue, rowObject)");
    sortFunction.AppendLine("{");
    sortFunction.AppendLine("return rowObject.RankID;");
    sortFunction.AppendLine("}");
Finally, the grid. I want to do my custom sort on the Rank column, so I add my custom property there.
 @Html.Grid(new GridControl()
            .SetName("grid")
            .SetPageSize(40)
            .SetIsAutoSize(true)
            .SetDataSource(ViewData["GridDataSource"])
            .SetColumns<Website.Models.MemberModels.MemberModel>(cs =>
                {
                    cs.Add(x => x.MemberID).SetAsPrimaryKey().SetHidden(true);
                    cs.Add(x => x.SN);
                    cs.Add(x => x.Rank).SetCustomAttributes(sortFunction.ToString());
                    cs.Add(x => x.LastName);
                    cs.Add(x => x.Initials);
                    cs.Add(x => x.Supervisor);
                    cs.Add(x => x.Instrument);
                    cs.Add(x => x.Effective);
                    cs.Add(x => x.AdminStatus);

                })
            );

Notice that I did not include RankID in my column list. All data is passed to the grid regardless if it is in the column list. But because it is not in the column list, it is not displayed.

 

Second Method:

In this method, you manual check the sort column and override it.

First here is my MemberModel used for this view:

 

    public class MemberModel
    {
        public Guid MemberID { get; set; }
        public int RankID { get; set; }
        public string Rank { get; set; }
        public string LastName { get; set; }
        public string Initials { get; set; }
    }

 

I've include the RankID in the presentation model here as it is the order I want my Ranks sorted.

Here is the List Method. It is basically a standard List method, but I've added a ApplyCustomSort method

       public ActionResult List(SearchModel searchModel)
        {
            
            IEnumerable<Member> memberEntities = _membersServices.GetAllMembers();
            IQueryable<MemberModel> members = _presentationMapper.Map<IEnumerable<Member>, IEnumerable<MemberModel>>(memberEntities).AsQueryable();

            ApplyCustomSort(ref searchModel, ref members);
            
            GridData gridData = members.ToGridData(searchModel);

            return Json(gridData, JsonRequestBehavior.AllowGet);

        }

Finally the meat of this, the ApplyCustomSort. This can be re factored to your liking but here is the general idea.

  • Check the searchModel for the column name you wish to apply a custom sorting (or multiple columns) to.
  • Check if it's asc or desc
  • If it matches your custom sort column, sort the data, and clear the searchModel so that the grid does not sort your data again.
  • Else, leave the searchModel alone and it will sort normally. As well, I like certain secondary column sorted no matter what the sort, so I do that sort on all data before sending it back.

 

        private void ApplyCustomSort(ref SearchModel searchModel, ref IQueryable<MemberModel> members)
        {
            if (searchModel.SortColumnName == "Rank")
            {
                if (searchModel.SortOrder == "asc")
                {
                    members = members.OrderByDescending(o => o.RankID).ThenBy(o => o.LastName).ThenBy(o => o.Initials);                    
                }
                else
                {
                    members = members.OrderBy(o => o.RankID).ThenByDescending(o => o.LastName).ThenByDescending(o => o.Initials);                    
                }
                searchModel.SortColumnName = "";
                searchModel.SortOrder = "";
            }
            else
            {
                members = members.OrderByDescending(o => o.RankID).ThenBy(o => o.LastName).ThenBy(o => o.Initials);
            }
        }

Finally, here is the grid. Currently there is no method (yet) in the API to specify the default column to sort by. The default is the first column. To get around this, we can add some AdditionalAttributes. This solution factors in the SetAdditionalAttributes fix.

@Html.Grid(new GridControl()
            .SetName("memberGrid")
            .SetPageSize(40)
            .SetIsAutoSize(true)
            .SetHeight("'100%'")
            .SetListUrl("Members/List")
            .SetOnSelectedRowEvent("window.location.href ='Members/Details/'+id;")
            .SetAdditionalAttributes(",sortname: 'Rank', sortorder: 'asc'")            
            .SetColumns<Website.Models.MemberModels.MemberModel>(cs =>
                {
                    cs.Add(x => x.MemberID).SetAsPrimaryKey().SetHidden(true); 
                    cs.Add(x => x.Rank);
                    cs.Add(x => x.LastName);
                    cs.Add(x => x.Initials);                                       
                })                
            )

That should be all you need to get you started on custom sorting. Enjoy!

 

Last edited Jun 3, 2011 at 5:27 PM by PhilmanCJ, version 1

Comments

No comments yet.