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.