Enhancing The WebGrid With Sort Arrows

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: 24857

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
Add your comment

If you have any comments to make about this article, please use this form to do so. Make sure that your comment relates specifically to the article above. More general comments can be posted through the form on the Contact page.

Please note, all comments are moderated, and I end up deleting quite a lot. The kind of things that will ensure your comment is deleted without ever seeing the light of day are as follows:

  • Requests to fix your code (post a question to forums.asp.net instead, please)
  • Gratuitous links to your own site or product
  • Anything abusive or libellous
  • Spam

I do not pass email addresses on to spammers, so a valid one will assist me in responding to you personally if required.

Recent Comments

faysal 3/3/2015 11:46 AM
In response to Inline Editing With The WebGrid
Nice one can you please tell us how we can do ad and delete functionality in this. for e.g if i on...

Fairoze Mohamed Musthafa 3/2/2015 8:33 AM
In response to Date formatting in VBScript
Appreciated !!!!...

mahdi 3/1/2015 10:16 AM
In response to Getting the identity of the most recently added record
Great Article....

Sohrab 2/28/2015 12:53 PM
In response to Displaying One-To-Many Relationships with Nested Repeaters
hi.this was very usefull for me.after spending 6 hours I could find best answer for my alot....

Abolfazl RoshanZamir 2/28/2015 10:36 AM
In response to Date Formatting in C#
very informative... thanks for sharing sir......

Oscar Duran 2/27/2015 2:00 PM
In response to How To Check If A Query Returns Data In ASP.NET Web Pages
Thank you very much Mike, this post has been very useful to me....

lama 2/27/2015 1:46 PM
In response to iTextSharp - Working with Fonts
thanks alot!! is it possible to add line height value to a paragraph ?...

Oded Dror 2/27/2015 5:23 AM
In response to MVC 5 with EF 6 in Visual Basic - Creating an Entity Framework Data Model
Hi there, Where I can find Contoso University Database? Thanks, Oded Dror...

hosein ey 2/25/2015 1:56 PM
In response to ASP.NET MVC 5 with EF 6 - Working With Files
tnx for this article do you think next version of entityframework support's the sql server and ?...

Saywer Ford 2/25/2015 5:15 AM
In response to Optimising ASP.NET Web Pages Sites - Bundling And Minification
Great Article. I did everything right and working fine. How about page specific js files. Lets I...