WebGrid Helper with Check All Checkboxes

    Introduction:



          WebGrid helper is one of the helper of ASP.NET Web Pages(WebMatrix) technology included in ASP.NET MVC 3. This helper is very easy to use and makes it very simple to display tabular data in your web page. In addition to displaying tabular data, it also supports formatting, paging and sorting features. But WebGrid helper does not allow you to put raw html(like checkbox) in the header. In this article, I will show you how you can put html element(s) inside the WebGrid helper's header using a simple trick. I will also show you how you can add the select or unselect all checkboxes feature in your web page using jQuery and WebGrid helper.  

 

    Description:

 

          To make it easy to add this feature in any of your web page, I will create an extension method for the WebGrid class. Here is the extension method,  

 

        public static IHtmlString GetHtmlWithSelectAllCheckBox(this WebGrid webGrid, string tableStyle = null,
string headerStyle = null, string footerStyle = null, string rowStyle = null,
	string alternatingRowStyle = null, string selectedRowStyle = null,
	string caption = null, bool displayHeader = true, bool fillEmptyRows = false,
	string emptyRowCellValue = null, IEnumerable<WebGridColumn> columns = null,
	IEnumerable<string> exclusions = null, WebGridPagerModes mode = WebGridPagerModes.All,
	string firstText = null, string previousText = null, string nextText = null,
	string lastText = null, int numericLinksCount = 5, object htmlAttributes = null,
	string checkBoxValue = "ID")
            {

                var newColumn = webGrid.Column(header: "{}",
                format: item => new HelperResult(writer =>
                {
                    writer.Write("<input class=\"singleCheckBox\" name=\"selectedRows\" value=\""
                    + item.Value.GetType().GetProperty(checkBoxValue).GetValue(item.Value, null).ToString()
                    + "\" type=\"checkbox\" />"
                    );
                }));

                var newColumns = columns.ToList();
                newColumns.Insert(0, newColumn);

                var script = @"<script>
                
                if (typeof jQuery == 'undefined')
                {
                    document.write(
                        unescape(
                        ""%3Cscript src='http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js'%3E%3C/script%3E""
                        )
                     );
                }

                (function(){

                    window.setTimeout(function() { initializeCheckBoxes();  }, 1000);
                    function initializeCheckBoxes(){    

                        $(function () {

                            $('#allCheckBox').live('click',function () {

                                var isChecked = $(this).attr('checked');                        
                                $('.singleCheckBox').attr('checked', isChecked  ? true: false);
                                $('.singleCheckBox').closest('tr').addClass(isChecked  ? 'selected-row': 'not-selected-row');
                                $('.singleCheckBox').closest('tr').removeClass(isChecked  ? 'not-selected-row': 'selected-row');

                            });

                            $('.singleCheckBox').live('click',function () {

                                var isChecked = $(this).attr('checked');
                                $(this).closest('tr').addClass(isChecked  ? 'selected-row': 'not-selected-row');
                                $(this).closest('tr').removeClass(isChecked  ? 'not-selected-row': 'selected-row');
                                if(isChecked && $('.singleCheckBox').length == $('.selected-row').length)
                                     $('#allCheckBox').attr('checked',true);
                                else
                                    $('#allCheckBox').attr('checked',false);

                            });

                        });
                    }

                })();
            </script>";

                var html = webGrid.GetHtml(tableStyle, headerStyle, footerStyle, rowStyle,
                                        alternatingRowStyle, selectedRowStyle, caption,
                                        displayHeader, fillEmptyRows, emptyRowCellValue,
                                        newColumns, exclusions, mode, firstText,
                                        previousText, nextText, lastText,
                                        numericLinksCount, htmlAttributes
                                        );

                return MvcHtmlString.Create(html.ToString().Replace("{}",
                                            "<input type='checkbox' id='allCheckBox'/>") + script);

            }

 

          This extension method accepts the same arguments as the WebGrid.GetHtml method except that it takes an additional checkBoxValue parameter. This additional parameter is used to set the values of checkboxes. First of all, this method simply insert an additional column(at position 0) into the existing WebGrid. The header of this column is set to {}, because WebGrid helper always encode the header text. At the end of this method, this text is replaced with a checkbox element.  

          In addition to emitting tabular data, this extension method also emit some javascript in order to make the select or unselect all checkboxes feature work. This method will add a css class selected-row for rows which are selected and not-selected-row css class for rows which are not selected. You can use these CSS classes to style the selected and unselected rows.

          You can use this extension method in ASP.NET MVC, ASP.NET Web Form and ASP.NET Web Pages(Web Matrix), but here I will only show you how you can leverage this in an ASP.NET MVC 3 application. Here is what you might need to set up a simple web page,

 

Person.cs

 

        public class Person
        {
            public int ID { get; set; }
            public string Name { get; set; }
            public string Email { get; set; }
            public string Adress { get; set; }
        }

 

IPersonService.cs

 

        public interface IPersonService
        {
            IList<Person> GetPersons();
        }

 

PersonServiceImp.cs

 

        public class PersonServiceImp : IPersonService
        {
            public IList<Person> GetPersons()
            {
                return _persons;
            }

            static IList<Person> _persons = new List<Person>();

            static PersonServiceImp()
            {
                for (int i = 5000; i < 5020; i++)
                    _persons.Add(new Person { ID = i, Name = "Person" + i, Adress = "Street, " + i, Email = "a" + i + "@a.com" });
            }
        }

 

HomeController.cs

 

        public class HomeController : Controller
        {
            private IPersonService _service;

            public HomeController()
                : this(new PersonServiceImp())
            {
            }

            public HomeController(IPersonService service)
            {
                _service = service;
            }

            public ActionResult Index()
            {
                return View(_service.GetPersons());
            }

            [HttpPost]
            public ActionResult Index(int[] selectedRows)
            {
                return View(_service.GetPersons());
            }

        }

 

Index.cshtml

 

        @model IEnumerable<WebGridHelperCheckAllCheckboxes.Models.Person>
        @{
            ViewBag.Title = "Index";
            Layout = "~/Views/Shared/_Layout.cshtml";
            var grid = new WebGrid(source: Model);
        }
        <h2>Index</h2>

        <style>
        .selected-row{
            background: none repeat scroll 0 0 #CACAFF;
            color: #222222;
        }
        .not-selected-row{
            background: none repeat scroll 0 0 #FFFFFF;
            color: #000000;
        }
        .grid
        {
            border-collapse: collapse;
        }
        .grid th,td
        {
            padding : 10px;
            border: 1px solid #000;
        }
        </style>

        @using (Html.BeginForm())
        {
            <fieldset>
                <legend>Person</legend>
                @grid.GetHtmlWithSelectAllCheckBox(
                    tableStyle: "grid", checkBoxValue: "ID",
                    columns: grid.Columns(
                        grid.Column(columnName: "Name"),
                        grid.Column(columnName: "Email"),
                        grid.Column(columnName: "Adress")
                ))
                <p>
                    <input type="submit" value="Save" />
                </p>
            </fieldset>
        }

 

          Now just run this application. You will find the following screen,  

 

         

 

          Select all or some rows of your table and submit them. You can get all the selected rows of your table as , 

 

         

 

 

        Summary:

          In ASP.NET MVC 3, you can utilize some helpers of ASP.NET Web Pages(WebMatrix) technology, which can be used for common functionalities. WebGrid helper is one of them. In this article, I showed you how you can add the select or unselect all checkboxes feature in ASP.NET MVC 3 application using WebGrid helper and jQuery. I also showed you how you can add raw html in WebGrid helper's header. Hopefully you will enjoy this article too. A sample application is attached.  

 

Published Tuesday, September 13, 2011 6:20 AM by imran_ku07

Comments

# re: WebGrid Helper with Check All Checkboxes

Saturday, September 24, 2011 6:21 AM by Kevin

Can you kindly show how to pull data from a model?

# re: WebGrid Helper with Check All Checkboxes

Saturday, September 24, 2011 10:52 AM by imran_ku07

@Kevin,

What do you mean?

# re: WebGrid Helper with Check All Checkboxes

Thursday, September 29, 2011 1:12 PM by jvboyd

Thanks for the code Imran.

Here's an issue I found recently. Everything works as expected for a "small" number of rows. When the row count gets over 2000 (2k), whenever you check a box, there's a delay of nearly 1/2 second. You can click as many boxes as you want, then you must sit back and wait/watch while they are all checked, one by one.

Any thoughts/ideas on what may be going on?

# re: WebGrid Helper with Check All Checkboxes

Friday, September 30, 2011 11:32 AM by jvboyd

Thannks for your quick response Imran!

I've attempted to utilize the new code you provided. A couple of quick notes:

- I'm getting a JS runtime error: "Object expected" for line "var checkBoxes = $('.singleCheckBox');

- If I click Continue in the error box, I do get the grid, though it appears to load slower, even on smaller record set.

- Ability to select all is no longer working, though selecting multiple boxes does seem to work.

- When I try with 2k records both the browser and my VS (Debug mode) lock up and I have to kill them both.

Yours is the best working option I've got so far so I'm hoping to be able to fully-use it.

Thanks for all your assistance.

# re: WebGrid Helper with Check All Checkboxes

Friday, September 30, 2011 3:17 PM by jvboyd

Imran, thanks again for your quick reply. I'm still having the same issues.

If you have any further thoughts/ideas please let me know. I'll do the same.

# re: WebGrid Helper with Check All Checkboxes

Friday, October 7, 2011 5:12 PM by jvboyd

yes, thank you. This does work. It is still slow but I think I have a workaround: paging

Do you have any thoughts on how to do that with your solution? Say, 20 records per page?

# re: WebGrid Helper with Check All Checkboxes

Friday, October 7, 2011 10:50 PM by imran_ku07

@jvboyd, see www.dotnetcurry.com/ShowArticle.aspx

# re: WebGrid Helper with Check All Checkboxes

Wednesday, October 12, 2011 5:50 PM by jvboyd

Thanks for all your assistance Imran! I've implemented a paging methodology that works with your extension method. With paging the checkboxes work much faster now with large sets of data.

# re: WebGrid Helper with Check All Checkboxes

Friday, October 14, 2011 10:48 AM by jvboyd

Imran, I changed your "src" line back to: src='ajax.googleapis.com/.../jquery.min.js'%3E%3C/script%3E""

because the latest way was giving JScript "object not found" error, FYI.

# re: WebGrid Helper with Check All Checkboxes

Friday, October 14, 2011 5:24 PM by bshardi

I am having trouble compiling the extension, format: item => new HelperResult(.. gives Argument3:Cannot convert from 'lambda expression' to 'System.Func<dynamic,object>'. I fear I am missing something?

I may need more instruction on how to setup the class?

# re: WebGrid Helper with Check All Checkboxes

Sunday, October 16, 2011 3:05 AM by imran_ku07

@bshardi

This code will only work in C#. For VB.NET, you need to translate this using C# to VB.NET translator

# re: WebGrid Helper with Check All Checkboxes

Sunday, October 16, 2011 3:10 AM by imran_ku07

@jvboyd, I don't see this error. Can you provide some more detail.

# re: WebGrid Helper with Check All Checkboxes

Monday, October 24, 2011 8:35 AM by sokolis

this method is not working in ajax callback.

# re: WebGrid Helper with Check All Checkboxes

Monday, October 24, 2011 12:48 PM by imran_ku07

@sokolis, Thanks, I have updated the code to use live instead of click.

# re: WebGrid Helper with Check All Checkboxes

Tuesday, November 1, 2011 2:39 PM by Tomas

This helper loose cheched columns on pagination, there is a way i cant loose it?

# re: WebGrid Helper with Check All Checkboxes

Tuesday, November 1, 2011 10:49 PM by imran_ku07

@Tomas

You can easily do this by adding some custom javascript but I think it is better for you to use PRG patteren.

# re: WebGrid Helper with Check All Checkboxes

Wednesday, November 2, 2011 11:27 PM by jvboyd

imran, I was getting the "Object not found" error with line:

src='ajax.googleapis.com/.../jquery.min.js'%3E%3C/script%3E""

Once I changed to: src" line back to: src='ajax.googleapis.com/.../jquery.min.js'%3E%3C/script%3E""

all worked fine for me. Could be related to some other jquery issue I had but I hadn't tried to track it down further once I made the change. If I get more information I'll post back. Thank you.

# re: WebGrid Helper with Check All Checkboxes

Thursday, November 17, 2011 4:00 AM by Tom

I'm using this code but when I sort the grid I get an error because of a checkbox on the page trying to bind a value of "true,false" due to the hidden field. It only does it when I sort or page the grid. Any ideas?

# re: WebGrid Helper with Check All Checkboxes

Friday, November 18, 2011 10:46 PM by imran_ku07

@Tom, I am getting this behaviour. Also Sorting will issue a GET request, so no hidden filed is sent.

# re: WebGrid Helper with Check All Checkboxes

Wednesday, January 18, 2012 1:38 PM by Lucas Reis

The code compiles here, but generates an error when accessing the page:

"Cannot perform runtime binding on a null reference"

Pointing to this line:

writer.Write("<input class=\"singleCheckBox\" name=\"selectedRows\" value=\"" + item.Value.GetType().GetProperty(checkBoxValue).GetValue(item.Value, null).ToString() + "\" type=\"checkbox\" />");

What may be going wrong?

Thanks in advance and congratulations for the blog and your achievements!

# re: WebGrid Helper with Check All Checkboxes

Wednesday, January 18, 2012 3:19 PM by Lucas Reis

Oops, problem solved! ;) I didn't have the "ID" field, and that was the problem.

Now, another doubt: how would we modify it to preserve the boxes checked even after some paging?

Thanks again!

# re: WebGrid Helper with Check All Checkboxes

Wednesday, January 18, 2012 10:36 PM by imran_ku07

@Lucas Reis, This makes no sense to preserve check boxes state after paging.

# re: WebGrid Helper with Check All Checkboxes

Thursday, January 19, 2012 6:56 AM by Lucas Reis

Maybe I didn't make myself clear: I have a database filled with many entries, and webgrid is showing 25 per page. I want make an "Export entries" function, that would write a XML file with all the entries selected. That's why I would like to preserve the check boxes state after paging! (like gmail, for example, does ;)

Thanks one more time for the attention! (and sorry for my english)

# re: WebGrid Helper with Check All Checkboxes

Thursday, January 19, 2012 7:34 AM by imran_ku07

@Lucas Reis,

Ok I will check that, if got some time. But you can easily add some jquery to make it work

# re: WebGrid Helper with Check All Checkboxes

Tuesday, March 6, 2012 4:50 PM by Matt

This code looks awesome.  I pasted your extension method into a static class in my project but I am getting an error on the semi colon on line 13 above saying Argument3: Cannot convert from 'Lamba Expression' to 'System.Func<dynamic,object>'.  Am I missing a step?

# re: WebGrid Helper with Check All Checkboxes

Tuesday, March 6, 2012 10:24 PM by imran_ku07

@Matt, download the sample

# re: WebGrid Helper with Check All Checkboxes

Wednesday, March 7, 2012 11:38 AM by Matt

Been trying to find a way to do this for a couple days now.  This works great!  Thank you so much!  I have 2 grids on my form so made a copy of the helper and changed the name and the name of the checkboxes and it passes both lists of selected checkboxes to my controller quickly and easily :).

# re: WebGrid Helper with Check All Checkboxes

Monday, March 26, 2012 9:37 PM by Frco

Hi sorry but I’m new I don’t know where to put the extension method code. Can you give me and example?

Thanks

# re: WebGrid Helper with Check All Checkboxes

Monday, March 26, 2012 11:06 PM by imran_ku07

@Frco, Download the sample application.

# re: WebGrid Helper with Check All Checkboxes

Thursday, March 29, 2012 6:15 PM by Michael

Hi Imran,

first a great thanks for providing this class. Pulling it over from your sample application and reverse-engineer the controller and the view part made it work within my app in about 60 minutes perfectly.

I have just noticed one thing: As I understand your class code, it seems to me that your class overrides the <tr>class which is set by the original WebGrid class through the alternatingRowStyle attribute.

As I am a true beginner with MVC, I have failed to manipulate your code correctly to detect an alternatingRowStyle <tr> row before it gets your selected-row or deselected-row class applied. (I don't understand completely the Syntax in these $() lines))

May I humbly ask if you would take the time to look into your code and to apply two additional styles so that there would be two new styles called: selected-row-Alternate and not-selected-row-Alternate

which would allow to still have an overlayed alternatingRowStyle even if a row is either selected or unselected?

This would greatly help the visibility of row reading.

With kind regards,

Michael

# re: WebGrid Helper with Check All Checkboxes

Friday, April 27, 2012 6:23 AM by Graham

Very useful example - thanks!

One thing I have found though is that if the grid is ajaxified (using the webgrid's ajaxUpdateContainerId parameter and a div to contain the grid) then after sorting the "check/uncheck all" feature stops working. (This is easy to demonstrate in the download.) Be grateful for anyone who can beat me to finding an answer :)

# re: WebGrid Helper with Check All Checkboxes

Friday, April 27, 2012 12:09 PM by Graham

Okay, found an answer to my previous question. Turns out that there is a ajaxUpdateCallback parameter for the webgrid. The trick is to change the script so that initializeCheckBoxes is no longer nested inside window.setTimeout, but is able to be called as a function in its own right. Then simply use initializeCheckBoxes as the parameter to ajaxUpdateCallback. Sorted! (Pun intended.)

# re: WebGrid Helper with Check All Checkboxes

Friday, April 27, 2012 12:12 PM by imran_ku07

@Graham, See in comments I have used live event instead

# re: WebGrid Helper with Check All Checkboxes

Monday, April 30, 2012 4:12 AM by Graham

Thanks for the note Imran, however I couldn't get sorting to work even with the revised code. The ajaxUpdateCallback method seems to work fine though.

Cheers - Graham

# re: WebGrid Helper with Check All Checkboxes

Monday, July 23, 2012 6:06 AM by Hardik

Thanks for the excellent blog Imran.

I am having the same issue as Lucas and I require to preserve checkbox state on paging. Let me know your feedback on this.

Thanks & Cheers - Hardik