Enhancing The WebGrid With Sort Arrows

4.64 (11 votes)

The Web Pages WebGrid offers sorting capability out of the box. However, it's not always obvious to the user on which column the grid data is being sorted at any one time, nor the direction in which it is being sorted. The convention is to provide arrows in the column header to act as a clear visual cue. This article looks at a three ways in which you can enhance your grids with sorting arrows.

The first approach uses a helper method to set the column header value:

@functions {
    public static string Sorter(string columnName, string columnHeader, WebGrid grid){
        return string.Format("{0} {1}", columnHeader, grid.SortColumn == columnName ? 
            grid.SortDirection == SortDirection.Ascending ? "▲" :
            "▼" : string.Empty);
    }
}

This function takes the column name, the column header value, and an instance of the WebGrid class. Here is how the function is used to set the column header value:

@{
    Page.Title = "Sorting Arrows";
    var db = Database.Open("Northwind");
    var sql = "SELECT CustomerID, CompanyName, ContactName, Address, City, Country, Phone FROM Customers";
    var data = db.Query(sql);
    var grid = new WebGrid(data, ajaxUpdateContainerId: "grid");
}
<h1>Sorting arrows</h1>
<div id="gridContainer">
    <div id="grid">
        @grid.GetHtml(    
            tableStyle : "table",
            alternatingRowStyle : "alternate",
            headerStyle : "header",
            columns: grid.Columns(
                grid.Column("CustomerID", Sorter("CustomerID", "ID", grid)),
                grid.Column("CompanyName", Sorter("CompanyName", "Company Name", grid)),
                grid.Column("ContactName", Sorter("ContactName", "Contact Name", grid)),
                grid.Column("Address", Sorter("Address", "Address", grid)),
                grid.Column("City", Sorter("City", "City", grid)),
                grid.Column("Country", Sorter("Country", "Country", grid)),
                grid.Column("Phone", Sorter("Phone", "Phone", grid))
            )
        )
    </div>
</div>

The WebGrid class has a SortDirection property which returns the direction for any sorting operation currently in use. It also has a SortColumn property which returns the name of the column which the data is being sorted on. The Sorter helper method inspects whether the current column is the one being sorted on, and if it is, it checks the current SortDirection value of the grid. Based on that, the column header value will be decorated with a triangle character indicating the direction. This method is simple to implement but it suffers from two main drawbacks: it has to be applied to every column individually, and it can only work with strings. There is no way to set apply an image as a direction indicator.

The next approach uses jQuery to solve the first of the drawbacks - it allows for centralisation of the code. The grid.GetHtml() method is slightly different, in that the function is not needed for the column names:

<div id="gridContainer">
    <div id="grid">
        @grid.GetHtml(    
            tableStyle : "table",
            alternatingRowStyle : "alternate",
            headerStyle : "header",
            columns: grid.Columns(
                grid.Column("CustomerID", "ID"),
                grid.Column("CompanyName", "Company Name"),
                grid.Column("ContactName", "Contact Name"),
                grid.Column("Address"),
                grid.Column("City"),
                grid.Column("Country"),
                grid.Column("Phone")
            )
        )
        @Html.Hidden("dir", grid.SortDirection) @Html.Hidden("col", grid.SortColumn)
    </div>
</div>

In addition, two hidden fields have been added to the page. One will contain the current sort direction, and the other the current sort column. Finally, the WebGrid constructor includes a value for the ajaxUpdateCallback parameter:

var grid = new WebGrid(data, ajaxUpdateContainerId: "grid", ajaxUpdateCallback: "setArrows");

The ajaxUpdateCallback value is the name of a JavaScript function that will execute whenever the grid is updated via AJAX. Here is all of the script that will set the arrows:

<script type="text/javascript">
    
    function setArrows() {
        var dir = $('#dir').val();
        var col = $('#col').val();
        var header = $('th a[href*=' + col + ']');
        if (dir == 'Ascending') {
            header.text(header.text() + ' ▲');
        }
        if (dir == 'Descending') {
            header.text(header.text() + ' ▼');
        }
    };

</script>

The sort direction and column are retrieved from the hidden fields, and the column header for the sort column is identified using jQuery's attribute contains selector. Then the correct arrow is added to the column's text depending on the sort direction.

The final example provides the ability to set your own arrows through images rather than text. It is only a minor deviation from the previous example, in that the ajaxUpdateCallback method sets the html of the header rather than the text:

<script type="text/javascript">
    
    function setArrowImages() {
        var dir = $('#dir').val();
        var col = $('#col').val();
        var header = $('th a[href*=' + col + ']');
        if (dir == 'Ascending') {
            header.html(header.html() + ' <img src="/images/arrow-up.png" alt="Ascending" />');
        }
        if (dir == 'Descending') {
            header.html(header.html() + ' <img src="/images/arrow-down.png" alt="Descending" />');
        }
    };
</script>

The name of this callback function differs from the preceding one, so if you want to try this out for yourself using the code that accompanies this article, you should make sure that you amend the WebGrid constructor call to reference setArrowImages in the ajaxUpdateCallback parameter instead. The code itself is on GitHub.

 

Date Posted:
Last Updated:
Posted by:
Total Views to date: 31655

3 Comments

- Eric Sassaman

A CSS based variation, which alllows total control over the arrows (size, color, alignment, etc.) and one spot to tweak your arrow formatting:

1) Instead of header.text(header.text() + ' ▲'), set a CSS class: header.addClass("asc") and header.addClass("desc").

2) Then, some CSS:

th
{
paddding-right: 2em; /* make enough room for the arrow */
}

th a.asc:after, th a.desc:after
{
position: relative;
left: .4em; /* spacing between header and arrow */
bottom: .1em; /* raise it just a tad */
font-size: 0.75em; /* I like my arrows a tad smaller */
color: red;
}

th a.asc:after
{
content: '▲';
}

th a.desc:after
{
content: '▼';
}

The nice thing about position: relative is that you can tweak the left, bottom, top, and right arrow settings and the parent header margin will stay the same. Just make sure it's wide enough for your narrow columns too.

- Prabhu Somasundaram

I followed your steps for the sorting the webgrid. First approach worked well. But for the second and third approach, setArrowImages javascript function of ajaxUpdateCallback didnt have access to the form fields; in this case it is hidden fields. By the way my webgrid in partial view and render in the parent view using Ajax.

- Mike

@Prabhu Somasundaram

I have no idea what the problem is, and this isn't the right place to solve it. You should post a question to forums.asp.net or www.stackoverflow.com

Recent Comments

Jon 31/03/2016 21:36
In response to Exploring Prefix: A Free ASP.NET Profiling Tool
We had the exact same experience, finding multiple bugs in an application that we thought was pretty...

ranjith 31/03/2016 05:50
In response to A Better Way To Export Gridviews To Excel
Hello Mike. i am exporting from gridview, because i have some images in my gridview. but i am error...

Matt Watson 30/03/2016 22:19
In response to Exploring Prefix: A Free ASP.NET Profiling Tool
Glad you are loving it! Matt from Stackify...

Dmitry 28/03/2016 04:26
In response to Solved - The Microsoft.ACE.OLEDB.12.0 provider is not registered on the local machine
thank you about the VS 32-bit remark...

federico 26/03/2016 11:29
In response to Request.Form Is Empty When Posting To ASPX Page
thanks!....

Micheal 23/03/2016 00:58
In response to ASP.NET MVC 5 with EF 6 - Working With Files
Thanks for the code. its pretty straightforward. worked for me on my first trial. Perfect!...

Francisco 22/03/2016 20:35
In response to ASP.NET MVC 5 with EF 6 - Working With Files
The post is very good, thanks...

Nick Brown 22/03/2016 13:53
In response to Adding A View
Hi, Many thanks for this tutorial, it's helping me get started with MVC. In VB (VS 2013) I get late...

ferry mae 22/03/2016 13:04
In response to Send form content by email in ASP.NET
do i need to change this? message.To.Add(new MailAddress("me@domain.com")); message.CC.Add(new you...

Keith 22/03/2016 12:02
In response to Creating a Connection String and Working with SQL Server LocalDB
As always worst explanation, but this time you rocked with plagiarism too .. huhh.. copied from Rick...