Inline Editing With The WebGrid
I have already looked at one approach to editing with the WebGrid, which involved invoking a jQuery dialog that contained a form. The approach covered in this article differs in that each row of data is presented as read-only, but converted to an editable format within the WebGrid so that the user doesn't have to leave the WebGrid to make their alterations:

The key to this approach is to populate the grid with both readonly and editable versions of the data, then to use the jQuery toggle command to swap between the two presentations on a line-by-line basis. So I need data prepared for dropdown lists when the page first loads as well as data to be displayed in read-only mode:
@{ var db = Database.Open("Books"); var books = db.Query(@"SELECT b.BookId, b.Title, b.ISBN, b.AuthorId, b.CategoryId, a.FirstName + ' ' + a.LastName AS AuthorName, c.Category FROM Books b INNER JOIN Authors a ON b.AuthorId = a.AuthorId INNER JOIN Categories c ON b.CategoryId = c.CategoryId ORDER BY b.BookId DESC"); var categories = db.Query("SELECT CategoryId, Category FROM Categories") .Select(category => new SelectListItem { Value = category.CategoryId.ToString(), Text = category.Category }); var authors = db.Query("SELECT AuthorId, FirstName + ' ' + LastName AS AuthorName FROM Authors") .Select(author => new SelectListItem { Value = author.AuthorId.ToString(), Text = author.AuthorName }); var grid = new WebGrid(books); }
The code gets three sets of data - the books details that I want to display, the collection of categories that the books can belong to and the authors that the books have been written by. The last two sets of data are converted to Enumerable<SlectListItem>. This is so that they can be plugged directly into Html.DropDownList helpers. Finally, the books data is passed into a WebGrid. Here is the code for the grid:
@grid.GetHtml( tableStyle : "table", alternatingRowStyle : "alternate", selectedRowStyle: "selected", headerStyle : "header", columns : grid.Columns( grid.Column("", style: "col1", format: @<text> <button class="edit-book display-mode" id="@item.BookId">Edit</button> <button class="save-book edit-mode" id="@item.BookId">Save</button> </text>), grid.Column("Title", style: "col2", format: @<text> <span id="title" class="display-mode">@item.Title</span> @Html.TextBox("Title", item.Title, new {@class="edit-mode", size = 45}) </text>), grid.Column("AuthorName", header : "Author", style: "col3", format: @<text> <span id="authorname" class="display-mode">@item.AuthorName</span> @Html.DropDownList("AuthorId", null, authors, item.AuthorId, new {@class="edit-mode"}) </text>), grid.Column("Category", style: "col4", format: @<text> <span id="category" class="display-mode">@item.Category</span> @Html.DropDownList("CategoryId", null, categories, item.CategoryId, new {@class="edit-mode"}) </text>), grid.Column("ISBN", style: "col5", format: @<text> <span id="isbn" class="display-mode">@item.ISBN</span> @Html.TextBox("ISBN", item.ISBN, new {@class="edit-mode", size = 20}) </text>) ) )
The main thing to take note of is that there are two items in each of the cells. In most of them, there is a span that holds the item for display, and a form element for editing the item. As I mentioned earlier, I am using the Html form helpers mainly because they require a lot less code than HTML itself. All items designed for display are given the CSS class "display-mode". The form fields have the CSS class of "edit-mode" applied to them. Both of the buttons in the first column are given two CSS classes.
The next part of the jigsaw is the jQuery code that manages switching between the two modes:
<script> $(function () { $('.edit-mode').hide(); $('.edit-book').on('click', function () { var tr = $(this).parents('tr:first'); tr.find('.edit-mode, .display-mode').toggle(); }); $('.save-book').on('click', function () { var tr = $(this).parents('tr:first'); var bookId = $(this).prop('id'); var title = tr.find('#Title').val(); var authorId = tr.find('#AuthorId').val(); var categoryId = tr.find('#CategoryId').val(); var isbn = tr.find('#ISBN').val(); $.post( '/EditBook', { BookId: bookId, Title: title, AuthorId: authorId, CategoryId: categoryId, ISBN: isbn }, function (book) { tr.find('#title').text(book.Title); tr.find('#authorname').text(book.AuthorName); tr.find('#category').text(book.Category); tr.find('#isbn').text(book.ISBN); }, "json"); tr.find('.edit-mode, .display-mode').toggle(); }); }) </script>
The first thing this script does is to hide all items with a CSS class of edit-mode resulting in all of the form fields and the Save button being hidden. An event handler is hooked up to the click event of the Edit button. This gets a reference to the table row that the button is in, and then toggles the visibility of all items within it that have a CSS class of edit-mode and display-mode. Since all edit-mode items were hidden at the outset, they now become visible, and all display items are hidden.
The next section of jQuery code applies an event handler to the click event of the Save button. Like the previous event handler, it obtains a reference the the current row, and then obtains values from the form fields and dropdowns as well as the ID of the current item from the Save button itself (which has been applied to its id attribute). It then packages these values and posts them to a page called EditBook.cshtml. Notice the absence of <form> tags in the code; jQuery takes care of constructing the POST request. Then it takes the data that the EditBook page returns and uses that to update the spans containing the displayed data. Finally, the edit-mode and display-mode items in the current row have their visibility toggled once again.
Here is the code for the EditBook.cshtml file:
@{ var bookId = Request["BookId"]; var title = Request["Title"]; var authorId = Request["AuthorId"]; var categoryId = Request["CategoryId"]; var isbn = Request["ISBN"]; var db = Database.Open("Books"); var sql = "UPDATE Books SET Title = @0, AuthorId = @1, CategoryId = @2, ISBN = @3 WHERE BookId = @4"; db.Execute(sql, title, authorId, categoryId, isbn, bookId); sql = @"SELECT b.Title, b.ISBN, a.FirstName + ' ' + a.LastName AS AuthorName, c.Category FROM Books b INNER JOIN Authors a ON b.AuthorId = a.AuthorId INNER JOIN Categories c ON b.CategoryId = c.CategoryId WHERE BookId = @0"; var result = db.QuerySingle(sql, bookId); Json.Write(result, Response.Output); }
It takes the values from the Request collection, and uses them to update the database table. Then it retrieves the data back from the database suitably shaped for display. Finally, the Json helper is used to send that data back to the calling code for consumption.
The code for this article is available at GitHub.
Currently rated 4.70 by 10 people
Rate Now!
Date Posted:
13 November 2012 10:37
Last Updated:
14 December 2012 20:01
Posted by:
Mikesdotnetting
Total Views to date:
9699



Comments
13 November 2012 15:23 from Nasir Raza
Great break through, I was looking this kind of code in web pages. Keep it up.
However, code for the article is not available. I think you have yet to publish it...
13 November 2012 16:04 from Mikesdotnetting
Apologies, the download link should work now.
13 November 2012 16:25 from Nasir Raza
Thanks, its working now.
14 November 2012 10:42 from Adrien Sleeg
Very interesting article !!
But the download link doesn't work for me...
14 November 2012 13:20 from Mikesdotnetting
I've revised the link to point to this site. Previously, the download was being hosted on Sky Drive.
15 November 2012 21:07 from yousaid
Great article !! Now how do you add a "Cancel" Functionality to the Edit mode. This is needed for those scenarios where the user changes their mind in the middle of the process.
Guess this is rather something very simple.
cheers,
yousaid
16 November 2012 06:08 from Mikesdotnetting
You just need to add another button with the class "cancel", and then alter the edit-book click event to include items with a class of cancel:
$('.edit-book, cancel').on('click', function () {
///
30 November 2012 07:15 from Emre
Hi this is really good work.Thanks for this.But i have a problem with sorting when i use this as u say.When i click headers to sort all hidden edit fields are opening.Do you have an idea for this why can i handle this problem?
13 December 2012 06:02 from Om Prakash Bishnoi
Thanks, nice and very interesting article !!
31 December 2012 22:45 from Marco
How would u handle validation?
01 January 2013 20:15 from Mikesdotnetting
@Marco,
That's not an easy question to answer in a comment, and would very much depend on what is required.
03 January 2013 16:29 from upen
this is really good, and how long are you in MVC ?
03 January 2013 16:32 from Mikesdotnetting
@upen,
I don't understand what you are asking. Sorry.
20 February 2013 11:14 from Sithelo
Thanks a lot for an eye opener tutorial. In my application, I combined the inline and search functionality. Now when I click the edit button, it show the Save button for a spilt second.
In short the edit functionality s somehow hindered. How can I work around this?
01 March 2013 20:26 from Patrick
Just what I needed! Thank you very much!!
06 March 2013 05:37 from kkDubey
It's good...but where is stylesheet (edit-mode,display-mode,etc..)?
06 March 2013 05:59 from Mikesdotnetting
@kkDubey
The CSS classes you mentioned were not used for setting styles in the sample. They were simply used as selectors for jQuery. You can apply whatever style you like to them, though.
09 April 2013 21:55 from Isaac Koss
Unfortunately this does not work in MVC 4. Do you have any ideas on how to do this in MVC 4? Thanks very much for your posts.