Conflicts between ASP.NET AJAX UpdatePanels & jQuery functions
In one of my previous posts dealing with the jQuery DatePicker , a user commented reporting an issue where he uses the jQuery DatePicker and ASP.NET AJAX UpdatePanels.
He says: On the same control that I have the date picker, I also have an ajax update panel, with sync as well as asych triggers. The date pick works before I trigger any ajax, and doesn't work after. Any clue of a workaround here?
Only two hours after his comment, I’ve replied with solution that I’ve used previously in one of my testing projects since I already experienced the same issue with some JavaScript functions previously.
So, once you see the issue, you will think that ASP.NET AJAX UpdatePanels does not like the other jQuery functions within the page. Hmm… it seems true, because after partial post-back has been made by the ASP.NET AJAX UpdatePanel, the JavaScript event handlers are lost.
First of all, we should avoid mixing different JavaScript libraries or frameworks because we may always have some issues when they override some of the default functions they use or some other conflicts that even we cannot think of. Also, both jQuery and ASP.NET Ajax use the dollar ($) sign in different context, which might be an issue when mixing both of the technologies on a single page.
Well, in order to reproduce the problem, lets pass trough the following steps:
1. Add reference to the jQuery library. If you don’t have the library on your local machine, you can reference it from the Microsoft Content Delivery Network (CDN)
<script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.min.js" type="text/javascript"></script>
2. The ASPX code - ScriptManager, UpdatePanel, Label and Button
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:Label runat="server" ID="lblText" />
<br />
<asp:Button ID="btnClick" runat="server" Text="Click Me" OnClick="btnClick_Click" />
</ContentTemplate>
</asp:UpdatePanel>
<br /><br />
<%= DateTime.Now %>
<!-- the Date time won't change on button click since its outside of the update panel -->
</div>
3. The jQuery function that will show an Alert when clicking on the Button
$(function () {
$("#btnClick").click(function () {
//will run on btnClick, which is inside the UpdatePanel
alert("Alert: Hello from jQuery!");
});
});
</script>
4. The server-side C# code that will run when the partial post back occurs, on button click event
{
lblText.Text = "Hello from the Server! Current Date&Time: " + DateTime.Now;
}
As you can see, I have mixed both technologies, the ASP.NET AJAX UpdatePanels and the jQuery that has event bound to the button inside the UpdatePanel.
Once we run the website, here is what happens:
- The website runs and the following screen will show up
- Click on the “Click Me” button and the following alert message will pop up (the jQuery function is called)
- Right after the client-side code is executed, the UpdatePanel will trigger partial postback event to the server and the result will be
- Now, we click the “Click Me” button again, but there is no Alert message anymore, even though we were expecting the alert. Partial postback has been done again and the server returns new message (see the date time difference)
The problem is reproduced, now lets explain what has happened.
After the page was loaded for first time, everything seems ok. The jQuery function waits till the DOM is fully loaded and then binds its event to the button click. However, the button is inside ASP.NET Ajax UpdatePanel which’s content will get reloaded once the partial post-back is triggered, which actually causes the event handlers to get lost.
I’ve seen few blogs where developers have posted some workarounds. I will post three different methods to resolve this so that you can use the one which seems more suitable for your application.
Method 1
The first method is by using the PageRequestManager. With the request manager, we can add an End Request event handler once the page has loaded after the partial post back is finished.
Here is how:
We need to write additional two JavaScript functions
- load() – which will add the End Request event using the Page Request Manager and will register the jsFunctions function
- jsFunctions() function which will reload the jQuery functions
function load() {
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(jsFunctions);
}
function jsFunctions() {
$("#btnClick").click(function () {
alert("Alert: Hello from jQuery!");
});
}
</script>
and we need to add
which will call the load() function once the onload event occurs.
Method 2
ASP.NET Ajax has one pageLoad() method which invokes the Sys.Application.load load event. Think of the pageLoad() event similar to the Page_Load server-side event that runs on code-behind in server. Only the pageLoad() event runs on client-side, everytime the page is reloaded (no matter if the reload is full or partial). If we put the script inside this event, it will avoid all the conflicts that happen between ASP.NET Ajax and the jQuery because it will rebind the scripts every time the page will do post-back.
<script language="javascript" type="text/javascript">
function pageLoad()
{
$(function () {
$("#btnClick").click(function () {
alert("Alert: Hello from jQuery!");
});
});
}
</script>
This seems definitely better than the first method since its more clear, you don’t need to create additional functions that will run on end request and you don’t need to add onload event to the body element.
Method 3
I won’t show anything new in this third method, but, I will show a way how to register the script from method 2 on server-side.
{
//I've formatted the JS function to be more readable ;)
string javaScriptFunction =
"function pageLoad() {" +
"$(function () {" +
"$('#btnClick').click(function () {" +
"alert('Alert: Hello from jQuery!');" +
"});" +
"});" +
"}";
ClientScript.RegisterStartupScript(this.GetType(), "myScript", javaScriptFunction, true);
}
I have added the script in the javaScriptFunction string, but you can add your scripts in an external JavaScript (.js) file and reference it using ClientScript.RegisterClientScriptInclude() function, so in such case we will have:
{
ClientScript.RegisterClientScriptInclude(this.GetType(), "myScript", "Scripts/javaScriptFile.js");
}
where the Scripts/javaScriptFile.js is the script file.
Note: There are some other methods too, such as using the jQuery live() function.
COMPLETE CODE
Here is the complete code implemented as in Method 2 with commented code lines for the last method with the server-side code.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Conflicts between ASP.NET AJAX Update Panels & JavaScript/jQuery functions</title>
<script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.min.js" type="text/javascript"></script>
</head>
<body>
<script language="javascript" type="text/javascript">
function pageLoad() {
$(function () {
$("#btnClick").click(function () {
alert("Alert: Hello from jQuery!");
});
});
}
</script>
<form id="form1" runat="server">
<div>
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:Label runat="server" ID="lblText" />
<br />
<asp:Button ID="btnClick" runat="server" Text="Click Me" OnClick="btnClick_Click" />
</ContentTemplate>
</asp:UpdatePanel>
<br /><br />
<%= DateTime.Now %>
<!-- the Date time won't change on button click since its outside of the update panel -->
</div>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
#region if you want to use your script in server side, uncomment the code inside this region
/*
string javaScriptFunction =
"function pageLoad() {" +
"$(function () {" +
"$('#btnClick').click(function () {" +
"alert('Alert: Hello from jQuery!');" +
"});" +
"});" +
"}";
ClientScript.RegisterStartupScript(this.GetType(), "myScript", javaScriptFunction, true);
*/
#endregion
#region if you have your JS script in an external file and want to reference it, uncomment the following line
//ClientScript.RegisterClientScriptInclude(this.GetType(), "myScript", "Scripts/javaScriptFile.js");
#endregion
}
protected void btnClick_Click(object s, EventArgs e)
{
lblText.Text = "Hello from the Server! Current Date&Time: " + DateTime.Now;
}
</script>
</form>
</body>
</html>
So, that’s it.
Even though the implementation is pretty simple, I made this blog post quite long in order to explain the details with trying not to get out of the problem boundaries.
I would like to note that I'm a big fun and I work a lot with both, the Microsoft ASP.NET Ajax and the jQuery library.
I hope this was helpful.
Kind Regards,
Hajan