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

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

Allen Michaels 12/17/2014 4:37 PM
In response to Cascading DropDownLists with jQuery and ASP.NET
Fantastic thank you so much!...

Emily 12/17/2014 12:36 PM
In response to Parameterized IN clauses with ADO.NET and LINQ
Thanks, very helpful!!!! Can i use this for multiple in's ????? IN (.....) and IN(...) and IN...

sss 12/16/2014 3:06 PM
In response to Solving the Operation Must Use An Updateable Query error
good...

Gjuro 12/15/2014 10:30 PM
In response to Examining the Edit Methods and Edit View
You have one fromr (and it should be from, I suppose). :-)...

Gjuro 12/15/2014 10:27 PM
In response to Adding Search
Hi, thnx for all this C#->VB translations. Yet, the following code block is (slightly) in error it a...

Scot 12/14/2014 1:39 PM
In response to Entity Framework 6 Recipe - Alphabetical Paging In ASP.NET MVC
Thanks,Mike I found solution....

Gjuro 12/13/2014 10:52 PM
In response to Accessing Your Model's Data from a Controller
The article mentions "Creating an Entity Framework Data Model for an ASP.NET MVC Application" (at is...

Samuel 12/13/2014 8:40 AM
In response to Displaying The First n Characters Of Text
I have failed to use the extension because it throws an error that it doesn't recognise the chop be...

Ignas 12/12/2014 5:11 PM
In response to Cleaner Conditional HTML Attributes In Razor Web Pages
Any suggestions for Html Helper elements with HtmlAttributes, when you need to conditionally set it...

Gautam 12/11/2014 8:50 PM
In response to Validation In Razor Web Pages 2
Hi Mike Is this required for V3, non html helper input...