A short while back I made a quick post on how to create a GridView with a column of checkboxes, then I created a JQuery function to check all of those at once. The idea being that I wanted reduce post-backs on the page.
Well, I had to revisit that idea today. My problem wasn’t with the Check All button that I made, that works fine, the problem was with the the check boxes in the grid view column themselves. I was using the built in Asp.Net AJAX UpdatePanel to handle talking to the code behind EVERY time a check box what checked.
Worked fine on small grids with good connections. But large grids with bad connections…not so much. The problem was that the entire grid was being reloaded with every check box click. Not good. If you want to see more reasons on why to beware UpdatePanel see Encosia’s “Why ASP.Net AJAX UpdatePanels are Dangerous“.
My solution was to replace the call-back/post-back with a JavaScript function and a WebService call. Now, I have a web service class called (wait for it): WebService.asmx. I’m going to use the ScriptManager to help me with this, by adding my WebService class to the ScriptManager’s Services node.
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<asp:ServiceReference Path="WebService.asmx" />
</Services>
</asp:ScriptManager>
This tells the ScriptManager to generate some JavaScript wrappers that will make calling my web service call easier. Bonus, I have my script manager in my Master Page, so now I can call this web service class from any content page. Otherwise, I could change ScriptManager to ScriptManagerProxy and do the same thing on specific pages.
So, I have to add a web service method to my WebService class that I can call from JavaScript. Here you go:
[WebMethod][ScriptMethod]
public void Reviewed(string userName, bool reviewed)
{
// calls my database wrapper class that executes the sql command.
// but I don't want to get into that right now, just go look up LINQ to SQL
// or NHibernate, or SubSonic, or ...
_dbo.Reviewed(userName, reviewed);
}
OK, that is the first easy part. I now have a web service that I can call from my JavaScript. Let’s move onto the next easy part. Hooking up a CheckBox control to execute the web service.
First thing I’m going to do is create a small JavaScript function on the page that actually calls the web service method. I’ll call it Reviewed:
<script type="text/javascript">
function Reviewed(ctrl, UserName) {
var isCheck = ctrl.checked;
WebService.Reviewed(UserName,isCheck);
}
</script>
Next comes up hooking up the CheckBox. Now, if all I had to do was set the onclick property to call the function, it would be easy. The code would look like this:
<asp:CheckBox ID="ReviewedCheckBox" CssClass="ApprovalCheckBox" runat="server" onclick='CallJavacriptfunction(this)' />
But I need more data than that. I also need to username. Plus, this is in a GridView. So I actually have to catch the OnRowDataBound event, and set the attribute programmatically.
protected void gvTimecard_RowDataBound(Object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
string clickEventText = "Reviewed(this, \"{0}\");";
string currentUser = HttpContext.Current.User.Identity.Name;
clickEventText = string.Format(clickEventText, currentUser );
CheckBox cb = (CheckBox)e.Row.FindControl("ReviewedCheckBox");
cb.Attributes["onclick"] = clickEventText;
}
}
And that is really about it. This will now call the web service from the check box, using JavaScript, but without any post backs at all. As a bonus, I’m passing around just the data that I need to execute the function. No ViewState, no reloading the entire grid.
Much, much, much better.
bm
The next question being is how to return something from the webservice.
if you webservice.reviewed returned a string “hello world”, how would you retrieve the string “hello world” and bring it back to the javascript function?
Hey Scott,
I’m doing that right now, but I’m using the Microsoft AJAX ScriptManager to do it. The ScriptManager wraps all of that for me very nicely. The key to remember is that you get the data back as part of a callback method, not directly from the method itself.
So if you call a WebService method
[System.Web.Script.Services.ScriptService]
public class JobService: System.Web.Services.WebService
{
[ScriptMethod]
public List GetJobs(string forUserId)
{
return new List();
}
}
You will setup the scriptmananger like this:
Then, your Javascript will look like this:
function CallWebService(userId) {
FSDispatchWeb.JobService.GetJobs(userId, OnJobsRetrieved);
}
function OnJobsRetrieved(jobList) {
// do something with jobList array
}
But if you want a JQuery way of calling a web service, you would use the $.ajax method