The WebGrid Helper - Making Selections

The WebGrid helper, introduced via ASP.NET Web Pages, provides a means for displaying tabular data easily. This article examines how to enable selection within the WebGrid at row level.

The scenario is a common one - you want to display summary data within a table on a web page, and you want to provide your user with a means by which they can view more detailed information on a particular item in the table, or make changes, such as editing or deleting an item. With the Web Forms GridView, this is easily accomplished by ticking boxes that automatically enable selection, editing and deleting. It's also pretty easy to do with the WebGrid. First, let's take a look at a typical WebGrid which displays some data from a database containing information on Books:

Here's the code for the page:

@{
    Layout = "/Shared/_Layout.cshtml";
    var db = Database.Open("Books");
    var sql = "Select BookId, Title, ISBN, Description, FirstName, LastName, Category From Books " + 
               "Inner Join Authors on Books.AuthorId = Authors.AuthorId " + 
               "Inner Join Categories on Books.CategoryId = Categories.CategoryId";
    var data =  db.Query(sql);
    var grid = new WebGrid(data);
}
<div id="grid">
@grid.GetHtml(
    tableStyle : "table",
    alternatingRowStyle : "alternate",
    headerStyle : "header",
    columns: grid.Columns(

        grid.Column(
            columnName : "Author",
            format: @<text>@item.FirstName @item.LastName</text>
            ),
        grid.Column(
            columnName : "Title",
            format: @<text>@item.Title</text>
            ),
        grid.Column(
            columnName : "Category"
            )
    )
)
</div>

If you are not familiar with how to set the basic properties of a WebGrid through Razor code, you should review my previous article on the WebGrid helper. If you want to allow your users to edit items, you ideally want to provide a column which contains a selection link like this:

The WebGridRow object has a GetSelectLink method which provides the means to do this. All you need to do is add another column to the grid and call the method. Here's the revised grid code with an additional column and a selectedRowStyle value set:

@grid.GetHtml(
    tableStyle : "table",
    alternatingRowStyle : "alternate",
    selectedRowStyle: "selected",
    headerStyle : "header",    
    columns: grid.Columns(
        grid.Column(
            header:"", 
            format:@<text>@item.GetSelectLink("Edit")</text>
            ),
        grid.Column(
            columnName : "Author",
            format: @<text>@item.FirstName @item.LastName</text>
            ),
        grid.Column(
            columnName : "Title",
            format: @<text>@item.Title</text>
            ),
        grid.Column(
            columnName : "Category"
            )
    )
)

Notice that the header property in the new column has been set to an empty string, and a string has been passed in to the GetSelectLink method ("Edit"). This string is the text that will appear on each row. You do not have to pass in a string. It is optional, but the default value is "Select" if you don't provide one yourself.

Great! But what happens if you click a link? At the moment, nothing happens except that the page refreshes, and the selected row takes on the colour specified in the css file. However, you might notice that the URL has changed a little in the browser eg:

The selected row is indicated in the querystring. The querystring key value "row" is set by default, but you can change this by applying your own value to the selectionFieldName property in your WebGrid constructor:

var grid = new WebGrid(data, selectionFieldName: "custom");
This would change the URL to read something like http://localhost:39612/Default.cshtml?custom=4. The presence of a selectionFieldName in the querystring (indicating that someone clicked the selection link) is tested using the WebGrid.HasSelection property:
@if(grid.HasSelection){
    //do something
}

In this example, I chose to use RenderPage to bring in the contents of another file, which contains a form for editing a book entry. In order to populate that form with the correct book details, I needed to pass the selected book to the partial page. This is done using the PageData dictionary mechanism:

@if(grid.HasSelection){
    var book = grid.SelectedRow;
    @RenderPage("~/Partials/EditBook.cshtml", new { Book = book } )
}

The code in EditBook.cshtml uses PageData to fetch the correct book, plus some other stuff from the database to populate the form ready for editing:

@{
    
    var bookid = Page.Book.BookId;
    var db = Database.Open("Books");    
    var authors = db.Query("SELECT AuthorId, FirstName + ' ' + LastName AS AuthorName FROM Authors");
    var categories = db.Query("SELECT CategoryId, Category FROM Categories");
    var sql = "SELECT BookId, Title, ISBN, Description, CategoryId, AuthorId, DatePublished FROM Books WHERE BookId = @0";
    var book = db.QuerySingle(sql, bookid);

}


    <form id="edit-book-form" action="@Href("~/Methods/EditBook")">
        <fieldset>
            <legend>Edit Book</legend>
         <div class="row">
                <span class="label"><label for="title">Title:</label></span>
                <input type="text" name="title" id="title" size="50" value="@book.Title" />
            </div>
            <div class="row">
                <span class="label"><label for="isbn">ISBN:</label></span>
                <input type="text" name="isbn" id="isbn" size="20" value="@book.ISBN" />
            </div>
            <div class="row">
                <span class="label"><label for="description">Description:</label></span>
                <textarea cols="50" rows="8" name="description" id="description">@book.Description</textarea>
            </div>
            <div class="row">
                <span class="label"><label for="authorId">Author:</label></span>
                <select name="authorId" id="authorId">
                    <option value="">-- Select Author --</option>
                @{
                    foreach(var author in authors){
                        if(author.AuthorId == book.AuthorId){
                            <option value="@author.AuthorId" selected="selected">@author.AuthorName</option>
                        } else {
                            <option value="@author.AuthorId">@author.AuthorName</option>
                        }
                    }
                }
                </select>
            </div>
            <div class="row">
                <span class="label"><label for="categoryId">Category:</label></span>
                <select name="categoryId" id="categoryId">
                    <option value="">-- Select Category --</option>
                @{
                    foreach(var category in categories){
                        if(category.CategoryId == book.CategoryId){
                            <option value="@category.CategoryId" selected="selected">@category.Category</option>
                        } else {
                            <option value="@category.CategoryId">@category.Category</option>
                        }        
                    }
                }
                </select>
            </div>
            <div class="row">
                <span class="label"><label for="datePublished">Date Published:</label></span>
                <input type="text" id="datePublished" name="datePublished" value="@book.DatePublished.ToString("d")" />
            </div>    
            <div class="row">
                <span class="label">&nbsp;</span>
                <input type="submit" id="submit" name="submit" value="Submit" />
            </div> 
            </fieldset>
        </form>

The resulting page looks like this:

There are alternatives to making rows selectable. For instance, you can use jQuery as illustrated in another of my previous articles. You would need to use a jQuery approach is you enable AJAX paging or sorting on the grid, as no querystring is generated when you click a link in the grid cells. Or you could simply format the text to include a hyperlink to another page:

grid.Column(
    header:"", 
    format:@<a href="/Edit/@item.BookId">Edit</a>)

If you wanted to provide more than one selection column, say an Edit and a Delete option, you would need to use this approach or the jQuery one, as currently, you cannot set the querystring selectFieldName property on a per column basis, so there will be no easy way to distinguish whether someone clicked the Edit link or the Delete link.

The full code is available in a download here.

Date Posted: Thursday, January 13, 2011 2:08 PM
Last Updated: Tuesday, November 11, 2014 8:15 AM
Posted by: Mikesdotnetting
Total Views to date: 24335

6 Comments

Saturday, January 15, 2011 8:26 AM - Max-B

It is possible to have an Edit and Delete link for the same row?

Saturday, January 15, 2011 8:28 AM - Max-B

Oh sorry! I don't read all find my way on this! Thanks for the good posts!!

Thursday, April 4, 2013 8:25 PM - Boyd Campbell

If I repopulate the grid with a brand new set of data, the WebGrid is keeping a handle on the previously selected row. IE: When I make a run to get a totally new set of data, all of the "Selected" related API's still have a row selected. This is causing an issue in my "if ( grid.HasSelection )" since it should not be hit at all after a new set of data.

How do I "reset" the state of the grid back to an unselected state?

Thursday, October 31, 2013 1:15 AM - ChrisL

Is it possible to make multiple selections with the WebGrid?

Tuesday, June 10, 2014 3:16 PM - Rex

Is there any possible way to set an "id" value to
format: @<text>@item.FirstName @item.LastName</text>

For example: format: @<text id = "someID">@item.FirstName @item.LastName</text>

I noticed that if i attempt the above example i will get an error. For what i am doing, i do not want render another page. I want to display a jquery modal dialog to the click event upon clicking "Edit/Select" and load some database information into the dialog using jquery ajax. To edit the data, i want to select the information using the row ID as this would be pivotal in loading the correct information. So Please let me know if there is a way to set an id to and get row information from the web grid.

If i used: format: @<a id = "someID" href = "#">"Edit"</a>
I will lose the row id information that is required for me to load the correct data on jquery ajax call

NOTE: I know this may be a difficult way around things and there are obviously much easier solutions, but bear with me and let me know if there are any solutions that meet my requirements.

Best Regards

Tuesday, June 10, 2014 3:35 PM - Mike

Rex,

Take a look at the following article: Inline Editing With The WebGrid. I apply dynamic Id values to rows in that.
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 some may not be published. The kind of things that will ensure your comment is deleted without ever seeing the light of day are as follows:

  • Not relevant to the article
  • Gratuitous links to your own site or product
  • Anything abusive or libellous
  • Spam
  • Anything in a language I don't understand including gibberish.

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

Gautam 11/20/2014 8:01 AM
In response to I'm Writing A Book On WebMatrix
Hello Mike, I read your book, loved it! However, I have a few request/suggestions: 1) an example...

Bret Dev 11/19/2014 8:39 PM
In response to The Difference Between @Helpers and @Functions In WebMatrix
Excellent post! One concern - where can you place global @Functions code within an MVC project to Is...

Rob Farquharson 11/19/2014 4:28 PM
In response to iTextSharp - Links and Bookmarks
How can I place text at an absolute position on the page? Also, how can I rotate text?...

Andy 11/17/2014 8:08 PM
In response to MVC 5 with EF 6 in Visual Basic - Sorting, Filtering and Paging
Hello I'm testing your sorting instructions above. This is great and I was able to get it to work...

Gautam 11/17/2014 5:51 PM
In response to WebMatrix - Database Helpers for IN Clauses
Hi Mike, I am very new to programming: In the above example if I want to use a delete button the...

donramon 11/17/2014 3:22 PM
In response to Entity Framework 6 Recipe - Alphabetical Paging In ASP.NET MVC
Congratulations on your new website look and the excellent articles. Thank you!...

Gautam 11/17/2014 11:26 AM
In response to Looking At The WebMatrix WebGrid
Hi Mike, I add the jquery script at the end of my html file.. when ajax attribute is added to the be...

Chet Ripley 11/15/2014 6:57 PM
In response to Adding A New Field
It appears the command is case sensitive. I had the same issue as Cameron. When I changed the to it...

Alvin 11/14/2014 12:49 PM
In response to Razor Web Pages E-Commerce - Adding A Shopping Cart To The Bakery Template Site
Great article Mike! When do you plan to extend the bakery shopping cart beyond this point?...

Gautam 11/14/2014 10:16 AM
In response to Web Pages - Efficient Paging Without The WebGrid
to get the count can we use only the below sql, why to join category and author table var sql =...