Javascript not work after firing Updatepanel in asp.net - javascript

My website's template is based on bootstrap and in the nav menu, I used the below code for some effects!
$('.productbar .dropdown').on('show.bs.dropdown', function (e) {
$(this).find('.dropdown-menu').first().stop(true, true).fadeIn(300);
$(this).find('.dropdown-menu').first().stop(true, true).animate({ top: "45px" }, 300);
});
$('.productbar .dropdown').on('hide.bs.dropdown', function (e) {
$(this).find('.dropdown-menu').first().stop(true, true).fadeOut(300);
$(this).find('.dropdown-menu').first().stop(true, true).animate({ top: "55px" }, 300);
$(this).find('.sub-menu').hide();
$(this).find('.left-caret').addClass("right-caret").removeClass("left-caret");
});
After firing the action button, updatepanel will fire and after this, the menu effect doesn't work!
What is the solution?

This occurs due to the Partial Postback using UpdatePanel. The Events that you subscribe for the controls are rendered partially hence the events looses. To overcome this situation you need to rebind the control events.
This is a common problem caused by mixing the conventional ASP.Net Ajax and jQuery events. When you do the partial postback, the DOM is recreated and the jQuery events are lost.
Example:
<script type="text/javscript">
// bind the events (jQuery way)
$(document).ready(function() {
bindEvents();
});
// attach the event binding function to every partial update
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(function(evt, args) {
bindEvents();
});
<script/>
Read More about PageRequest Manager on MSDN
Here bindEvents() method contains all the script that you need to reload again after Partial Page Postback.
Hope this helps you!

I faced the same problem. I got help from this link. Execute JavaScript when an UpdatePanel is updated
protected void Page_Load(object sender, EventArgs e)
{
ScriptManager.RegisterStartupScript(
upPanel,
this.GetType(),
"MyAction",
"doMyAction();",
true);
}
The first parameter is the UpdatePanel
The second parameter is a type parameter
The third parameter, “MyAction”, is a key to identify the script.
script itself.
The final parameter is a flag to indicate whether the ScriptManager should wrap your code in script tags.

If the above does not work, this should reload the events on any postback (partial or full).
Wrap your entire jquery DOM ready event function in the following:
function pageLoad() {
$(document).ready(function () {
//jquery code and events, event binding.. etc..
}); }
This can be helpful if you have many asp:update panels..

Related

Bootstrap tooltips stop working whenever anything is clicked on the page

On my page, I initialize Bootstrap tooltips this way
<script>
$(document).ready(function () {
$(function () {
$('[data-toggle="tooltip"]').tooltip();
});
});
</script>
This question suggests that any time an event happens you have to reload tooltips. However, across various ajax page updating there are probably 50+ events to account for. (This site is using asp.net web forms and ajaxcontroltoolkit)
How can I universally reinitiate tooltips every time an event takes place? -- or is there a simpler solution to solving this problem?
You need a javascript reference to Sys.WebForms.PageRequestManager
Take a look at the beginRequest/endRequest events. Since asp.net ajax is replacing your html you'll need to rebind the bootstrap widgets after asp.net is finished with its ajax.
Try this:
<script>
var prm = Sys.WebForms.PageRequestManager.getInstance();
//func to rebind tooltip
function reBind () { $('[data-toggle="tooltip"]').tooltip(); }
$(document).ready(function () {
$(function () {
reBind();
prm.add_endRequest(reBind);
});
});
</script>
Be warned some bootstrap widgets will break if they are bound twice, so use your discretion; some elements might need to have their events monitored to see if they are bound more than once.

Javascript code stopped working inside a ASP.NET user control with Update Panel

I have a Javascript code that is used for a full gridview row clicking to check a checkbox in the same row. (Placed in an external file)
$(document).ready(function () {
$('tr.dataRow').on('click', function () {
var checked = $(this).find('input[id*=chkBusinessSelected]').prop('checked');
$(this).find('input[id*=chkBusinessSelected]').prop('checked', !checked);
});
});
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(function () {
$('tr.dataRow').on('click', function () {
var checked = $(this).find('input[id*=chkBusinessSelected]').prop('checked');
$(this).find('input[id*=chkBusinessSelected]').prop('checked', !checked);
});
});
In the code behind of the User Control
protected void grdBusiness_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
e.Row.CssClass = "dataRow";
}
}
Take note that they are enclosed in an Update Panel to avoid full Postback. The function is for multiple selecting an item in a gridview. Everything worked well as is, until I used the User control in a parent page where in, that page has an Update Panel usage also.
Using the gridview row clicking functionality and click another button outside the user control to process something. Upon using or repeating the function again, I cannot click the checkbox already. The Javacript code stopped working.
I tried removing the UpdatePanel on the parent page, and it worked. But I needed to put Update panel both in the User Control and the Parent page.
For jQuery 1.7+ you can attach an event handler to a parent element using .on(), and pass the a selector combined with 'dataRow' as an argument.
See http://api.jquery.com/on/
So instead of...
$('tr.dataRow').click( function() {
// do something
});
You can write...
$('body').on('click', 'tr.dataRow', function() {
// do something
});
Not you can write it outside the $(document).ready(function () { also.
If you are using older version you can use .live() method of jQuery.
More detail Event binding on dynamically created elements?

jQuery Mobile - how to force that page recreation - pagebeforecreate event

I have a small jQuery mobile site.
it's all single .html file
it's has some edit functionality (view, edit, save)
all works with ajax/json/web service
Most of my pages are using data from web service, via AJAX & JSON, so I am using the following a lot:
$(document).on( 'pagebeforecreate', '#monday', function() {
// do some stuff on before create, load data with AJAX
});
Now, how do I FORCE that page recreation (pagebeforecreate event) so the AJAX inside is run again (get the latest data from server)?
Use pageBeforeShow instead of pageBeforeCreate.
From the jqm documentation, about creation events.
Note that these events will only fire once per "page", as opposed to the show/hide events, which fire every time a page is shown and hidden.
I recommend creating a function that you can call when the pagebeforecreate event fires and whenever else you want to update the site:
function myUpdateFunc() {
// load data w/ AJAX
}
$(document).on('pagebeforecreate', '#monday', function () {
//do some stuff on `pagebeforecreate`
myUpdateFunc();
});
Now you can call the myUpdateFunc() function from anywhere in the scope that it's declared.
Also, you can use .trigger() to trigger an event, to run the code in an event handler for the event:
$('#monday').trigger('pagebeforecreate');
Force page recreation/refresh with this code:
function refreshPage() {
$.mobile.changePage(
window.location.href,
{
allowSamePageTransition : true,
transition : 'none',
showLoadMsg : false,
reloadPage : true
}
);
}
Taken and tested from here.

Hooking a javascript function to every postback

This is some Javascript added on an .aspx page:
<Head>
<script>
function SayHello()
{
alert('Hello');
}
</script>
and here is how I am calling it from code:
protected void Page_Init(object sender, Eventargs e)
{
Page.ClientScript.RegisterStartupScript(Page.GetType(),"script","SayHello()",true);
}
The problem is that the Javascript function is called only one time, on the very first page load. I want it to be called on every post back. for example on every button click
Create a subclass of the Button control and use that on your pages. It has the OnClientClick property which you can already preset in your subclass.
I would recommend a pure JavaScript method, such as adding the call to the Javascript function in the body onload event:
<body onload="sayHello();">
Or using the jQuery library to hook onto the document's onready event:
$(document).ready(function() { sayHello(); });
You can simply use onload event:
<body onload="SayHello()">
</body>
...
If you are using UpdatePanel (AJAX), then you should register script like this:
System.Web.UI.ScriptManager.RegisterStartupScript(page, page.GetType(), "key", "SayHello()", true);

jQuery $(document).ready and UpdatePanels?

I'm using jQuery to wire up some mouseover effects on elements that are inside an UpdatePanel. The events are bound in $(document).ready . For example:
$(function() {
$('div._Foo').bind("mouseover", function(e) {
// Do something exciting
});
});
Of course, this works fine the first time the page is loaded, but when the UpdatePanel does a partial page update, it's not run and the mouseover effects don't work any more inside the UpdatePanel.
What's the recommended approach for wiring stuff up in jQuery not only on the first page load, but every time an UpdatePanel fires a partial page update? Should I be using the ASP.NET ajax lifecycle instead of $(document).ready?
An UpdatePanel completely replaces the contents of the update panel on an update. This means that those events you subscribed to are no longer subscribed because there are new elements in that update panel.
What I've done to work around this is re-subscribe to the events I need after every update. I use $(document).ready() for the initial load, then use Microsoft's PageRequestManager (available if you have an update panel on your page) to re-subscribe every update.
$(document).ready(function() {
// bind your jQuery events here initially
});
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(function() {
// re-bind your jQuery events here
});
The PageRequestManager is a javascript object which is automatically available if an update panel is on the page. You shouldn't need to do anything other than the code above in order to use it as long as the UpdatePanel is on the page.
If you need more detailed control, this event passes arguments similar to how .NET events are passed arguments (sender, eventArgs) so you can see what raised the event and only re-bind if needed.
Here is the latest version of the documentation from Microsoft: msdn.microsoft.com/.../bb383810.aspx
A better option you may have, depending on your needs, is to use jQuery's .on(). These method are more efficient than re-subscribing to DOM elements on every update. Read all of the documentation before you use this approach however, since it may or may not meet your needs. There are a lot of jQuery plugins that would be unreasonable to refactor to use .delegate() or .on(), so in those cases, you're better off re-subscribing.
<script type="text/javascript">
function BindEvents() {
$(document).ready(function() {
$(".tr-base").mouseover(function() {
$(this).toggleClass("trHover");
}).mouseout(function() {
$(this).removeClass("trHover");
});
}
</script>
The area which is going to be updated.
<asp:UpdatePanel...
<ContentTemplate
<script type="text/javascript">
Sys.Application.add_load(BindEvents);
</script>
*// Staff*
</ContentTemplate>
</asp:UpdatePanel>
User Control with jQuery Inside an UpdatePanel
This isn't a direct answer to the question, but I did put this solution together by reading the answers that I found here, and I thought someone might find it useful.
I was trying to use a jQuery textarea limiter inside of a User Control. This was tricky, because the User Control runs inside of an UpdatePanel, and it was losing its bindings on callback.
If this was just a page, the answers here would have applied directly. However, User Controls do not have direct access to the head tag, nor did they have direct access to the UpdatePanel as some of the answers assume.
I ended up putting this script block right into the top of my User Control's markup. For the initial bind, it uses $(document).ready, and then it uses prm.add_endRequest from there:
<script type="text/javascript">
function BindControlEvents() {
//jQuery is wrapped in BindEvents function so it can be re-bound after each callback.
//Your code would replace the following line:
$('#<%= TextProtocolDrugInstructions.ClientID %>').limit('100', '#charsLeft_Instructions');
}
//Initial bind
$(document).ready(function () {
BindControlEvents();
});
//Re-bind for callbacks
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(function() {
BindControlEvents();
});
</script>
So... Just thought someone might like to know that this works.
Upgrade to jQuery 1.3 and use:
$(function() {
$('div._Foo').live("mouseover", function(e) {
// Do something exciting
});
});
Note: live works with most events, but not all. There is a complete list in the documentation.
You could also try:
<asp:UpdatePanel runat="server" ID="myUpdatePanel">
<ContentTemplate>
<script type="text/javascript" language="javascript">
function pageLoad() {
$('div._Foo').bind("mouseover", function(e) {
// Do something exciting
});
}
</script>
</ContentTemplate>
</asp:UpdatePanel>
,since pageLoad() is an ASP.NET ajax event which is executed each time the page is loaded at client side.
My answer?
function pageLoad() {
$(document).ready(function(){
etc.
Worked like a charm, where a number of other solutions failed miserably.
I would use one of the following approaches:
Encapsulate the event binding in a function and run it every time you update the page. You can always contain the event binding to specific elements so as not to bind events multiple times to the same elements.
Use the livequery plug-in, which basically performs method one for you auto-magically. Your preference may vary depending on the amount of control you want to have on the event binding.
function pageLoad() is very dangerous to use in this situation. You could have events become wired multiple times. I would also stay away from .live() as it attaches to the document element and has to traverse the entire page (slow and crappy).
The best solution I have seen so far is to use jQuery .delegate() function on a wrapper outside the update panel and make use of bubbling. Other then that, you could always wire up the handlers using Microsoft's Ajax library which was designed to work with UpdatePanels.
When $(document).ready(function (){...}) not work after page post back then use JavaScript function pageLoad in Asp.page as follow:
<script type="text/javascript" language="javascript">
function pageLoad() {
// Initialization code here, meant to run once.
}
</script>
I had a similar problem and found the way that worked best was to rely on Event Bubbling and event delegation to handle it. The nice thing about event delegation is that once setup, you don't have to rebind events after an AJAX update.
What I do in my code is setup a delegate on the parent element of the update panel. This parent element is not replaced on an update and therefore the event binding is unaffected.
There are a number of good articles and plugins to handle event delegation in jQuery and the feature will likely be baked into the 1.3 release. The article/plugin I use for reference is:
http://www.danwebb.net/2008/2/8/event-delegation-made-easy-in-jquery
Once you understand what it happening, I think you'll find this a much more elegant solution that is more reliable than remembering to re-bind events after every update. This also has the added benefit of giving you one event to unbind when the page is unloaded.
FWIW, I experienced a similar issue w/mootools. Re-attaching my events was the correct move, but needed to be done at the end of the request..eg
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(function() {...
Just something to keep in mind if beginRequest causes you to get null reference JS exceptions.
Cheers
pageLoad = function () {
$('#div').unbind();
//jquery here
}
The pageLoad function is perfect for this case since it runs on the initial page load and every updatepanel async postback. I just had to add the unbind method to make the jquery work on updatepanel postbacks.
http://encosia.com/document-ready-and-pageload-are-not-the-same/
My answer is based on all the expert comments above, but below is the following code that anyone can use to make sure on each postback and on each asynchronous postback the JavaScript code will still be executed.
In my case, I had a user control within a page. Just paste the below code in your user control.
<script type="text/javascript">
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(EndRequestHandler);
function EndRequestHandler(sender, args) {
if (args.get_error() == undefined) {
UPDATEPANELFUNCTION();
}
}
function UPDATEPANELFUNCTION() {
jQuery(document).ready(function ($) {
/* Insert all your jQuery events and function calls */
});
}
UPDATEPANELFUNCTION();
</script>
Update Panel always replaces your Jquery with its inbuilt Scriptmanager's scripts after every load. Its better if you use pageRequestManager's instance methods like this...
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(onEndRequest)
function onEndRequest(sender, args) {
// your jquery code here
});
it will work fine ...
Use below script and change the body of the script accordingly.
<script>
//Re-Create for on page postbacks
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(function () {
//your codes here!
});
</script>
In response to Brian MacKay's answer:
I inject the JavaScript into my page via the ScriptManager instead of putting it directly into the HTML of the UserControl. In my case, I need to scroll to a form that is made visible after the UpdatePanel has finished and returned. This goes in the code behind file. In my sample, I've already created the prm variable on the main content page.
private void ShowForm(bool pShowForm) {
//other code here...
if (pShowForm) {
FocusOnControl(GetFocusOnFormScript(yourControl.ClientID), yourControl.ClientID);
}
}
private void FocusOnControl(string pScript, string pControlId) {
ScriptManager.RegisterStartupScript(this.Page, this.Page.GetType(), "focusControl_" + pControlId, pScript, true);
}
/// <summary>
/// Scrolls to the form that is made visible
/// </summary>
/// <param name="pControlId">The ClientID of the control to focus on after the form is made visible</param>
/// <returns></returns>
private string GetFocusOnFormScript(string pControlId) {
string script = #"
function FocusOnForm() {
var scrollToForm = $('#" + pControlId + #"').offset().top;
$('html, body').animate({
scrollTop: scrollToForm},
'slow'
);
/* This removes the event from the PageRequestManager immediately after the desired functionality is completed so that multiple events are not added */
prm.remove_endRequest(ScrollFocusToFormCaller);
}
prm.add_endRequest(ScrollFocusToFormCaller);
function ScrollFocusToFormCaller(sender, args) {
if (args.get_error() == undefined) {
FocusOnForm();
}
}";
return script;
}
Sys.Application.add_load(LoadHandler); //This load handler solved update panel did not bind control after partial postback
function LoadHandler() {
$(document).ready(function () {
//rebind any events here for controls under update panel
});
}
For anyone else in my situation, I was trying to get jquery document ready function to work for a DevExpress ASPxCallbackPanel and nothing above (to-date) worked. This is what did work for me.
<script>
function myDocReadyFunction(){ /* do stuff */ }
</script>
<dx:ASPxCallbackPanel ID="myCallbackPanel" ... >
<ClientSideEvents EndCallback="function(){ myDocReadyFunction();}">
</ClientSideEvents>
<PanelCollection ...>
</dx:ASPxCallbackPanel>

Categories