jQuery $ (document) .ready und UpdatePanels?

475

Ich verwende jQuery, um einige Mouseover-Effekte für Elemente in einem UpdatePanel zu verkabeln. Die Ereignisse sind eingebunden $(document).ready. Zum Beispiel:

$(function() {    
    $('div._Foo').bind("mouseover", function(e) {
        // Do something exciting
    });    
});

Dies funktioniert natürlich beim ersten Laden der Seite einwandfrei, aber wenn das UpdatePanel eine teilweise Seitenaktualisierung durchführt, wird es nicht ausgeführt und die Mouseover-Effekte funktionieren im UpdatePanel nicht mehr.

Was ist der empfohlene Ansatz, um Dinge in jQuery nicht nur beim Laden der ersten Seite zu verkabeln, sondern jedes Mal, wenn ein UpdatePanel eine teilweise Seitenaktualisierung auslöst? Sollte ich stattdessen den ASP.NET Ajax-Lebenszyklus verwenden $(document).ready?

Herb Caudill
quelle
Probieren
Baxterboom
1
Ähnlich wie bei dieser Frage: stackoverflow.com/questions/301473/…
Per Hornshøj-Schierbeck

Antworten:

545

Ein UpdatePanel ersetzt den Inhalt des Update-Panels bei einem Update vollständig. Dies bedeutet, dass die von Ihnen abonnierten Ereignisse nicht mehr abonniert werden, da das Update-Fenster neue Elemente enthält.

Um dies zu umgehen, habe ich die Ereignisse, die ich nach jedem Update benötige, erneut abonniert. Ich verwende es $(document).ready()für das anfängliche Laden und verwende dann Microsoft PageRequestManager(verfügbar, wenn Sie ein Update-Panel auf Ihrer Seite haben), um jedes Update erneut zu abonnieren.

$(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
});

Das PageRequestManagerist ein JavaScript - Objekt , das automatisch zur Verfügung, wenn ein Update - Panel auf der Seite. Sie sollten nichts anderes als den obigen Code tun müssen, um ihn zu verwenden, solange sich das UpdatePanel auf der Seite befindet.

Wenn Sie eine detailliertere Steuerung benötigen, übergibt dieses Ereignis Argumente, die der Übergabe von .NET-Ereignissen ähneln, (sender, eventArgs)sodass Sie sehen können, was das Ereignis ausgelöst hat, und nur bei Bedarf erneut binden können.

Hier ist die neueste Version der Dokumentation von Microsoft: msdn.microsoft.com/.../bb383810.aspx


Eine bessere Option, die Sie je nach Ihren Anforderungen haben können, ist die Verwendung von jQuery's .on(). Diese Methoden sind effizienter als das erneute Abonnieren von DOM-Elementen bei jedem Update. Lesen Sie jedoch die gesamte Dokumentation, bevor Sie diesen Ansatz verwenden, da er möglicherweise Ihren Anforderungen entspricht oder nicht. Es gibt eine Menge von jQuery - Plugins , die auf refactor zu verwenden unangemessen wären , .delegate()oder .on()in den Fällen, so, du ist besser dran Wiederzeichn.

Dan Herbert
quelle
1
Bitte seien Sie genauer, wenn Sie eine Erklärung abgeben. Ich meine, ein Anwendungsbeispiel ist viel besser als ein paar verstreute Codezeilen. Siehe Brian MacKay Erklärung. Es ist perfekt!
Wahrheitssucher
3
@ Dan, Ab jQuery 1.7, .delegate()wurde von der.on()
Gabriele Petrioli
@ GabyakaG.Petrioli Mir ist klar, dass es ersetzt wurde, aber da diese Antwort ein häufiges Problem zu lösen scheint, wollte ich die Kompatibilität mit älteren Versionen von jQuery maximieren, die noch nicht aktualisiert wurden. Meine zuvor empfohlene Antwort, .live(...)die in 1.7 offiziell veraltet ist und in einer zukünftigen Version möglicherweise entfernt wird. Ich habe mich absichtlich dafür entschieden, .delegate()da es seit einiger Zeit in jQuery unterstützt wird und wahrscheinlich nicht so bald entfernt wird. Ich werde jedoch meine Antwort aktualisieren, um sie .on()auch für diejenigen zu erwähnen , die sie verwenden können.
Dan Herbert
12
Es ist besser, die PRM-Variable innerhalb des $ (Dokuments) zu deklarieren und zu verkabeln. Da das Sys möglicherweise noch nicht deklariert wurde (je nachdem, wo sich das Skript befindet).
Drake7707
1
@AhmedSamy Es wird nicht empfohlen, jQuery.delegate()mehr zu verwenden. Es wurde ersetzt, jQuery.on()welche API bevorzugt verwendet werden soll. delegate()ist einfach ein Wrapper für eine bestimmte Verwendung von on(), und es ist möglich, dass es in Zukunft veraltet sein wird. Mein vorheriger Kommentar delegate()wurde vor über einem Jahr geschrieben, als jQuery 1.7 (mit dem die on()API eingeführt wurde) neu veröffentlicht wurde. Da jQuery 1.9 bereits delegate()verfügbar ist und 2.0 in der Beta für die Veröffentlichung vorbereitet ist, ist es eine gute Idee, die Verwendung in neuem Code zu vermeiden .
Dan Herbert
159
<script type="text/javascript">

        function BindEvents() {
            $(document).ready(function() {
                $(".tr-base").mouseover(function() {
                    $(this).toggleClass("trHover");
                }).mouseout(function() {
                    $(this).removeClass("trHover");
                });
         }
</script>

Der Bereich, der aktualisiert werden soll.

<asp:UpdatePanel...
<ContentTemplate
     <script type="text/javascript">
                    Sys.Application.add_load(BindEvents);
     </script>
 *// Staff*
</ContentTemplate>
    </asp:UpdatePanel>
Barbaros Alp
quelle
Funktioniert gut für asp: GridView TextBox in <EditItemTemplate>
Dan Randolph
Das Problem bei dieser Lösung ist, dass der asynchrone Post des UpdatePanel zwar funktioniert, der asynchrone Beitrag jedoch nicht mehr angezeigt wird, wodurch das UpdatePanel erneut unbrauchbar wird. (Seufzer)
MC9000
63

Benutzersteuerung mit jQuery In einem UpdatePanel

Dies ist keine direkte Antwort auf die Frage, aber ich habe diese Lösung zusammengestellt, indem ich die Antworten gelesen habe, die ich hier gefunden habe, und ich dachte, jemand könnte sie nützlich finden.

Ich habe versucht, einen jQuery-Textbereichsbegrenzer in einem Benutzersteuerelement zu verwenden. Dies war schwierig, da das Benutzersteuerelement in einem UpdatePanel ausgeführt wird und beim Rückruf seine Bindungen verloren hat.

Wenn dies nur eine Seite wäre, wären die Antworten hier direkt zutreffend gewesen. Benutzersteuerelemente hatten jedoch weder direkten Zugriff auf das Head-Tag noch direkten Zugriff auf das UpdatePanel, wie einige der Antworten annehmen.

Am Ende habe ich diesen Skriptblock ganz oben im Markup meines Benutzersteuerelements platziert. Für die anfängliche Bindung wird $ (document) .ready verwendet, und dann wird prm.add_endRequest von dort verwendet:

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

Also ... Ich dachte nur, jemand möchte vielleicht wissen, dass das funktioniert.

Brian MacKay
quelle
2
Ich konnte das nicht für mein Leben zum Laufen bringen. Dann habe ich es vom Kopf in die Fußzeile verschoben und es hat funktioniert. Nicht positiv, aber ich denke, es musste nach dem von mir verwendeten ScriptManager kommen.
Adam Youngers
In meinem Fall habe ich das Skript mit ScriptManager.RegisterClientScriptBlock hinzugefügt, wodurch das Skript hinzugefügt wird, bevor Sys definiert ist. Daher habe ich stattdessen RegisterStartupScript verwendet (siehe Unterschied hier )
Firas Assaad
2
Coole Antwort! In meiner asp.net-Web-App hat es wie ein Zauber funktioniert. + für Sie
Pranesh Janarthanan
33

Aktualisieren Sie auf jQuery 1.3 und verwenden Sie:

$(function() {

    $('div._Foo').live("mouseover", function(e) {
        // Do something exciting
    });

});

Hinweis: Live funktioniert mit den meisten Ereignissen, aber nicht mit allen. Die Dokumentation enthält eine vollständige Liste .

svinto
quelle
Die Verwendung von Live behebt das Problem mit Update-Panels. Es mussten keine Reifen durchspringen.
Tim Scarborough
Was ist mit etwas, das beim Laden von Seiten passieren muss? Zum Beispiel Zebrastreifen? $ ('TABLE TR: n-tes Kind (ungerade)'). AddClass ('alt-row');
Adam Youngers
3
Nur zum Aktualisieren, seit jQuery 1.7 wird jetzt empfohlen, stattdessen .on () zu verwenden
George
1
live()Ich habe gerade einen schwerwiegenden Fehler bei der Verwendung der Methode in IE7 gefunden (jQuery 1.5.1 / VS2010-Projekt). Bei der Verwendung von live()in in einem Update v3.5 ASP.NET regelmäßig AutoPostbackvon <asp:DropDownList />Ursachen 2 partielle Postbacks in Bezug auf die erwarteten 1. Die zusätzlichen Postbacks durch den Browser ausgegeben Gegensatz fehlen den Inhalt (abgebrochen) verursachen die Page.IsPostBackzu sein false(welcher Zustand in meiner Schranke tötet Kontrollen). Ich fand den Täter live (). Mir ist klar, dass das erste Postback von UpdatePanel pro Spezifikation abgebrochen werden muss, aber nur, wenn es ein anderes in der Warteschlange gibt, das es nicht gibt.
timmi4sa
20

Sie könnten auch versuchen:

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

, da pageLoad () ein ASP.NET-Ajax-Ereignis ist, das jedes Mal ausgeführt wird, wenn die Seite auf der Clientseite geladen wird.

Daniel Hursan
quelle
pageLoad dupliziert die Ereignisse bei jedem ASync-Postback von Update Panel.
Zo hat
17

Meine Antwort?

function pageLoad() {

  $(document).ready(function(){

usw.

Arbeitete wie ein Zauber, bei dem eine Reihe anderer Lösungen kläglich scheiterten.

Jono
quelle
Perfekt für die Größenänderung der Textbereiche in meiner Listenansicht in meinem UpdatePanel in meinem UserControl entsprechend der Textmenge.
Ressource
Ich hatte Probleme damit, dass Dom-JQuery-Funktionen beim Postback mit Update-Panels ordnungsgemäß funktionieren. Diese Lösung funktionierte und ich musste meine Funktionsaufrufe in zwei Szenarien nicht duplizieren. Dies hielt die Abfragefunktionen und den Listener verfügbar. Hinweis Ich habe alle meine Skript- und JQuery-Bibliotheksinhalte direkt vor dem FORM [end] -Tag am Ende der Seite platziert. Vielen Dank!!!
moto_geek
7

Ich würde einen der folgenden Ansätze verwenden:

  1. Kapseln Sie die Ereignisbindung in eine Funktion und führen Sie sie jedes Mal aus, wenn Sie die Seite aktualisieren. Sie können die Ereignisbindung immer an bestimmte Elemente enthalten, um Ereignisse nicht mehrmals an dieselben Elemente zu binden.

  2. Verwenden Sie das Livequery- Plug-In, das die erste Methode für Sie automatisch ausführt. Ihre Präferenz kann abhängig von der Kontrolle variieren, die Sie über die Ereignisbindung haben möchten.

Eran Galperin
quelle
7

Das hat bei mir funktioniert:

$(document).ready(function() {

    // Do something exciting

    var prm = Sys.WebForms.PageRequestManager.getInstance();

    prm.add_endRequest(function() {
        // re-bind your jQuery events here
    });

});
Turbojohan
quelle
6

Die Funktion pageLoad () ist in dieser Situation sehr gefährlich. Es kann vorkommen, dass Ereignisse mehrmals verkabelt werden. Ich würde mich auch von .live () fernhalten, da es an das Dokumentelement angehängt wird und die gesamte Seite durchlaufen muss (langsam und beschissen).

Die beste Lösung, die ich bisher gesehen habe, ist die Verwendung der Funktion jQuery .delegate () auf einem Wrapper außerhalb des Update-Panels und die Verwendung von Bubbling. Abgesehen davon können Sie die Handler jederzeit mithilfe der Ajax-Bibliothek von Microsoft verkabeln, die für die Verwendung mit UpdatePanels entwickelt wurde.

Norm
quelle
6

Wenn Sie $(document).ready(function (){...})nach dem Zurücksenden der Seite nicht arbeiten, verwenden Sie die JavaScript-Funktion pageLoad in Asp.page wie folgt:

<script type="text/javascript" language="javascript">
function pageLoad() {
// Initialization code here, meant to run once. 
}
</script>
Pradeep Mehr
quelle
Ja, suchen Sie auch nach isPartialLoad: stackoverflow.com/questions/301473/…
Steve Greene
4

Ich hatte ein ähnliches Problem und fand, dass es am besten funktionierte, sich auf Event Bubbling und Event Delegation zu verlassen, um es zu lösen. Das Schöne an der Ereignisdelegierung ist, dass Sie nach dem Einrichten keine Ereignisse nach einem AJAX-Update erneut binden müssen.

In meinem Code richte ich einen Delegaten für das übergeordnete Element des Aktualisierungsfensters ein. Dieses übergeordnete Element wird bei einer Aktualisierung nicht ersetzt, und daher ist die Ereignisbindung nicht betroffen.

Es gibt eine Reihe guter Artikel und Plugins für die Ereignisdelegierung in jQuery, und die Funktion wird wahrscheinlich in die Version 1.3 integriert. Der Artikel / das Plugin, das ich als Referenz verwende, ist:

http://www.danwebb.net/2008/2/8/event-delegation-made-easy-in-jquery

Wenn Sie erst einmal verstanden haben, was passiert, werden Sie feststellen, dass dies eine viel elegantere Lösung ist, die zuverlässiger ist, als daran zu denken, Ereignisse nach jedem Update erneut zu binden. Dies hat auch den zusätzlichen Vorteil, dass Sie ein Ereignis zum Aufheben der Bindung erhalten, wenn die Seite entladen wird.

Joe Brinkman
quelle
4

FWIW, ich hatte ein ähnliches Problem mit Mootools. Das erneute Anhängen meiner Ereignisse war der richtige Schritt, musste jedoch am Ende der Anfrage erfolgen

var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(function() {... 

Nur etwas, das Sie beachten sollten, wenn beginRequest dazu führt, dass Sie JS-Ausnahmen mit Nullreferenz erhalten.

Prost


quelle
3
pageLoad = function () {
    $('#div').unbind();
    //jquery here
}

Die pageLoad-Funktion ist in diesem Fall perfekt, da sie beim ersten Laden der Seite und bei jedem asynchronen Postback des Updatepanels ausgeführt wird. Ich musste nur die Unbind-Methode hinzufügen, damit die Abfrage bei Updatepanel-Postbacks funktioniert.

http://encosia.com/document-ready-and-pageload-are-not-the-same/

Duane
quelle
2

Meine Antwort basiert auf allen Expertenkommentaren oben, aber unten ist der folgende Code, mit dem jeder sicherstellen kann, dass bei jedem Postback und bei jedem asynchronen Postback der JavaScript-Code weiterhin ausgeführt wird.

In meinem Fall hatte ich ein Benutzersteuerelement innerhalb einer Seite. Fügen Sie einfach den folgenden Code in Ihr Benutzersteuerelement ein.

<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>
Abhishek Shrivastava
quelle
2

Das Update Panel ersetzt Ihre JQuery nach jedem Laden durch die Skripte des eingebauten Scriptmanagers. Es ist besser, wenn Sie die Instanzmethoden von pageRequestManager wie diese verwenden ...

Sys.WebForms.PageRequestManager.getInstance().add_endRequest(onEndRequest)
    function onEndRequest(sender, args) {
       // your jquery code here
      });

es wird gut funktionieren ...

Rohit Sharma
quelle
Ein alter Beitrag, der mir aber geholfen hat. Eine Sache, die ich hinzufügen möchte: Der Speicherort des add_endRequest-Codes muss sich im UpdatePanel befinden, da der Sys.WebForms.PageRequestManager nur zu diesem Zeitpunkt verfügbar ist. Die eigentliche Funktion muss sich jedoch nicht an diesem Ort befinden. In meinem Fall habe ich also eine script.js-Datei, die den Code enthält, den ich binden möchte, und der in einer Funktion enthalten ist. In dieser script.js-Datei habe ich einen document.ready-Aufruf, der die obige Funktion aufruft. Dann habe ich in meinem UpdatePanel den Code add_endRequest, der auch die obige Funktion aufruft.
Kiran Ramaswamy
1

Verwenden Sie das folgende Skript und ändern Sie den Hauptteil des Skripts entsprechend.

       <script>
        //Re-Create for on page postbacks
        var prm = Sys.WebForms.PageRequestManager.getInstance();
        prm.add_endRequest(function () {
           //your codes here!
        });
    </script>
mzonerz
quelle
0

Als Antwort auf Brian MacKays Antwort:

Ich füge das JavaScript über den ScriptManager in meine Seite ein, anstatt es direkt in den HTML-Code des UserControl einzufügen. In meinem Fall muss ich zu einem Formular scrollen, das sichtbar wird, nachdem das UpdatePanel abgeschlossen und zurückgegeben wurde. Dies geht in den Code hinter der Datei. In meinem Beispiel habe ich die PRM- Variable bereits auf der Hauptinhaltsseite erstellt.

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;
}
Fujiiface
quelle
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
        });
}
Tony Dong
quelle