jQuery $(document).ready and UpdatePanels?
Asked Answered
U

18

488

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?

Ursine answered 1/11, 2008 at 22:24 Comment(2)
Give this a try i think it will solve your problem codeproject.com/Articles/21962/…Kudva
Similar to this question: #301973Phelps
V
557

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.

Vocalism answered 1/11, 2008 at 22:24 Comment(5)
@Dan, As of jQuery 1.7, .delegate() has been superseded by the .on()Monteith
@GabyakaG.Petrioli I realize it has been superseded, but since this answer seems to solve a common problem I wanted to maximize compatibility with older versions of jQuery that haven't been upgraded yet. My answer previously recommended .live(...) which has been officially deprecated in 1.7 and may be removed in a future version. I intentionally chose .delegate() since it has been supported in jQuery for a while now and is not likely to be removed any time soon. However, I'll upgrade my answer to mention .on() as well for those who can use it.Vocalism
It's better to declare and wire up the prm var inside the $(document).ready, as it's possible the Sys has not been declared yet (depending on where the script is).Porras
@AhmedSamy It is not recommended to use jQuery.delegate() any more. It has been superseded by jQuery.on() which is the preferred API to use. delegate() is simply a wrapper for a specific use of on(), and it's possible that it may become deprecated in the future. My previous comment mentioning delegate() was written over a year ago when jQuery 1.7 (which introduced the on() API) was newly released. With jQuery 1.9 already out and 2.0 in beta being prepared for release, it is a good idea to avoid using delegate() in any new code.Vocalism
This works, but the UpdatePanel no longer does partial page updates after implementing. I tried this with the Select2 bootstrap dropdown (and the bootstrap-select as well) and this defeats asynch (works fine on regular dropdownlist with no formatting or initialization - but desire a nice looking dropdown). The only solution was to ditch the updatepanel altogether and just use jquery ajax instead (MS just doesn't have a clue).Zonazonal
J
158
<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>
Jubbulpore answered 14/1, 2009 at 13:51 Comment(2)
Works well for asp:GridView TextBox inside <EditItemTemplate>Flodden
The problem with this solution, is that, while it works, it kills the UpdatePanel's asynchronous post back - making the UpdatePanel useless once again. (sigh)Zonazonal
A
64

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.

Anastigmat answered 26/5, 2010 at 19:53 Comment(2)
I couldn't get this to work for the life of me. Then I moved it from the head to the footer and it worked. Not positive, but I think it needed to come after the ScriptManager I am using.Philbin
In my case I was adding the script using ScriptManager.RegisterClientScriptBlock which adds the script before Sys is defined, so I ended up using RegisterStartupScript instead (see difference here)Declivous
B
33

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.

Botanize answered 6/2, 2009 at 0:54 Comment(4)
Using live fixes the issue with update panels. No hoops needed to jump through.Biotite
What about something that needs to happen on pageload? For example zebra striping tables? $('TABLE TR:nth-child(odd)').addClass('alt-row');Philbin
Just to update, since jQuery 1.7 it is now recommended to use .on() insteadCoitus
Just found a serious failure while using the live() method in IE7 (jQuery 1.5.1 / VS2010 project). When using live() inside an UpdatePanel in v3.5 ASP.NET a regular AutoPostback of <asp:DropDownList /> causes 2 partial postbacks as opposed to the expected 1. The extra postback issued by the browser lacks the content (aborted) causing the Page.IsPostBack to be false (which kills state inside my bound controls). I found the culprit to be live() method. I realize that 1st postback to be aborted by UpdatePanel per spec but only if there's another one in the queue of which there isn't.Genethlialogy
M
20

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.

Midwife answered 31/12, 2010 at 10:51 Comment(1)
pageLoad duplicate the events on every ASync postback of Update Panel.Outsoar
Z
17

My answer?

function pageLoad() {

  $(document).ready(function(){

etc.

Worked like a charm, where a number of other solutions failed miserably.

Zoometry answered 28/2, 2011 at 18:1 Comment(2)
Perfect for resizing the textareas in my Listview in my UpdatePanel in my UserControl according to amount of text.Undersigned
I struggled to make dom jquery functions work correctly on postback with update panels, this solution worked and I didn't have to duplicate my function calls in 2 scenarios. This kept the jquery functions and listener available. Note I put all my script and jquery library includes right before the FORM [end] tag at the bottom of the page. Thanks!!!Largo
O
7

I would use one of the following approaches:

  1. 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.

  2. 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.

Offhand answered 1/11, 2008 at 22:39 Comment(0)
L
6

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.

Lounging answered 17/6, 2011 at 15:17 Comment(0)
L
6

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>
Lightship answered 16/7, 2015 at 5:6 Comment(1)
Yes, check for isPartialLoad as well: #301973Banister
L
4

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.

Lalise answered 3/11, 2008 at 12:36 Comment(0)
C
4

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

Choosy answered 3/11, 2008 at 16:28 Comment(0)
S
3
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/

Solemn answered 23/7, 2014 at 2:18 Comment(0)
M
2

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>
Mellar answered 27/11, 2012 at 16:26 Comment(0)
O
2

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 ...

Overexpose answered 21/7, 2014 at 12:5 Comment(1)
An old post, but one which helped me out. One thing which I would like to add to this: the location of the add_endRequest code has to be inside the UpdatePanel, as the Sys.WebForms.PageRequestManager is only available at that point. However, the actual function does not need to be in that location. So, in my case, I have a script.js file which contains the code I want bound, contained within a function. In that script.js file, I have a document.ready call, which invokes the above function. Then, in my UpdatePanel, I have the add_endRequest code, which also invokes the above function.Doody
P
1

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>
Phycomycete answered 20/6, 2018 at 7:47 Comment(0)
M
0

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;
}
Mononuclear answered 4/6, 2013 at 21:10 Comment(0)
N
0
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
        });
}
Nellenelli answered 18/12, 2017 at 22:25 Comment(0)
B
0

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>
Barge answered 27/5, 2022 at 13:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.