jQuery $ (document) .ready e UpdatePanels?


475

Sto usando jQuery per collegare alcuni effetti del mouseover su elementi che si trovano all'interno di UpdatePanel. Gli eventi sono associati $(document).ready. Per esempio:

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

Naturalmente, questo funziona benissimo la prima volta che la pagina viene caricata, ma quando UpdatePanel esegue un aggiornamento parziale della pagina, non viene eseguito e gli effetti del passaggio del mouse non funzionano più all'interno di UpdatePanel.

Qual è l'approccio consigliato per il cablaggio di roba in jQuery non solo al caricamento della prima pagina, ma ogni volta che un UpdatePanel genera un aggiornamento parziale della pagina? Dovrei usare il ciclo di vita ASP.NET ajax invece di $(document).ready?



Risposte:


545

Un UpdatePanel sostituisce completamente il contenuto del pannello di aggiornamento su un aggiornamento. Questo significa che quegli eventi a cui ti sei iscritto non sono più iscritti perché ci sono nuovi elementi in quel pannello di aggiornamento.

Quello che ho fatto per ovviare a questo problema è di ri-abbonarmi agli eventi di cui ho bisogno dopo ogni aggiornamento. Uso $(document).ready()per il caricamento iniziale, quindi uso Microsoft PageRequestManager(disponibile se hai un pannello di aggiornamento sulla tua pagina) per abbonare nuovamente ogni aggiornamento.

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

La PageRequestManagerè un oggetto JavaScript che è automaticamente disponibile se un pannello di aggiornamento è sulla pagina. Non dovresti dover fare altro che il codice sopra per usarlo fintanto che UpdatePanel è sulla pagina.

Se hai bisogno di un controllo più dettagliato, questo evento passa argomenti simili a come gli eventi .NET vengono passati a argomenti in (sender, eventArgs)modo da poter vedere cosa ha generato l'evento e ricollegarlo solo se necessario.

Ecco l'ultima versione della documentazione di Microsoft: msdn.microsoft.com/.../bb383810.aspx


Un'opzione migliore che potresti avere, a seconda delle tue esigenze, è quella di utilizzare jQuery .on(). Questi metodi sono più efficienti della nuova iscrizione agli elementi DOM su ogni aggiornamento. Leggere tutta la documentazione prima di utilizzare questo approccio, poiché potrebbe soddisfare o meno le proprie esigenze. Esistono molti plug-in jQuery che potrebbero essere irragionevoli da utilizzare come refactor .delegate()o .on(), quindi, in questi casi, è meglio abbonarsi nuovamente.


1
Sii più preciso quando dai spiegazioni. Voglio dire che un esempio di utilizzo è molto meglio di una coppia di righe di codice sparse. Vedi la spiegazione di Brian MacKay. È perfetto!
Cercatore della verità,

3
@Dan, a partire da jQuery 1.7, .delegate()è stato sostituito da.on()
Gabriele Petrioli l'

@ GabyakaG.Petrioli Mi rendo conto che è stato sostituito, ma poiché questa risposta sembra risolvere un problema comune, ho voluto massimizzare la compatibilità con le versioni precedenti di jQuery che non sono ancora state aggiornate. La mia risposta in precedenza mi ha raccomandato .live(...)che è stato ufficialmente deprecato in 1.7 e potrebbe essere rimosso in una versione futura. Ho scelto intenzionalmente .delegate()poiché è stato supportato in jQuery per un po 'di tempo e probabilmente non verrà rimosso presto. Tuttavia, aggiornerò la mia risposta per menzionarla .on()anche per coloro che possono usarla.
Dan Herbert,

12
È meglio dichiarare e collegare il prm var all'interno del $ (documento). Come è possibile, il Sys non è stato ancora dichiarato (a seconda di dove si trova lo script).
drake7707,

1
@AhmedSamy Non è consigliabile utilizzare jQuery.delegate()più. È stato sostituito da jQuery.on()quale è l'API preferita da usare. delegate()è semplicemente un wrapper per un uso specifico di on()ed è possibile che possa diventare obsoleto in futuro. Il mio precedente commento menzionato è delegate()stato scritto più di un anno fa quando jQuery 1.7 (che ha introdotto l' on()API) è stato appena rilasciato. Con jQuery 1.9 già in uscita e 2.0 in beta in preparazione per il rilascio, è una buona idea evitare di utilizzare delegate()qualsiasi nuovo codice.
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>

L'area che verrà aggiornata.

<asp:UpdatePanel...
<ContentTemplate
     <script type="text/javascript">
                    Sys.Application.add_load(BindEvents);
     </script>
 *// Staff*
</ContentTemplate>
    </asp:UpdatePanel>

Funziona bene per asp: GridView TextBox all'interno di <EditItemTemplate>
Dan Randolph

Il problema con questa soluzione è che, mentre funziona, elimina il post asincrono di UpdatePanel, rendendo inutilizzabile UpdatePanel. (sospiro)
MC9000,

63

Controllo utente con jQuery all'interno di UpdatePanel

Questa non è una risposta diretta alla domanda, ma ho messo insieme questa soluzione leggendo le risposte che ho trovato qui e ho pensato che qualcuno potesse trovarlo utile.

Stavo cercando di utilizzare un limitatore di textarea jQuery all'interno di un controllo utente. Ciò è stato complicato, poiché il controllo utente viene eseguito all'interno di un UpdatePanel e perde i collegamenti al callback.

Se questa fosse solo una pagina, le risposte qui sarebbero state applicate direttamente. Tuttavia, i controlli utente non hanno accesso diretto al tag head, né hanno avuto accesso diretto a UpdatePanel come alcune delle risposte presuppongono.

Ho finito per mettere questo blocco di script proprio nella parte superiore del markup del mio controllo utente. Per il bind iniziale, utilizza $ (document) .ready e quindi utilizza prm.add_endRequest da lì:

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

Quindi ... Ho pensato che qualcuno potesse piacere sapere che funziona.


2
Non riuscivo a farlo funzionare per la vita di me. Poi l'ho spostato dalla testa al piè di pagina e ha funzionato. Non positivo, ma penso che debba venire dopo lo ScriptManager che sto usando.
Adam Youngers,

Nel mio caso stavo aggiungendo lo script usando ScriptManager.RegisterClientScriptBlock che aggiunge lo script prima della definizione di Sys, quindi ho finito per usare invece RegisterStartupScript (vedi la differenza qui )
Firas Assaad

2
Bella risposta! ha funzionato come un fascino nella mia app web asp.net. + per te
Pranesh Janarthanan,

33

Esegui l'upgrade a jQuery 1.3 e utilizza:

$(function() {

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

});

Nota: live funziona con la maggior parte degli eventi, ma non tutti. C'è un elenco completo nella documentazione .


L'uso di live risolve il problema con i pannelli di aggiornamento. Non sono necessari cerchi per saltare.
Tim Scarborough,

Che dire di qualcosa che deve accadere al pageload? Ad esempio tavoli zebrati? $ ('TABELLA TR: nth-child (dispari)'). AddClass ('alt-row');
Adam Youngers,

3
Solo per aggiornare, dal momento che jQuery 1.7 ora si consiglia di utilizzare .on () invece
George

1
Ho appena riscontrato un errore grave durante l'utilizzo del live()metodo in IE7 (progetto jQuery 1.5.1 / VS2010). Quando si utilizza live()all'interno di un UpdatePanel in ASP.NET v3.5 un normale AutoPostbackdi <asp:DropDownList />cause 2 postback parziali rispetto al previsto 1. Il postback aggiuntivo emesso dal browser manca del contenuto (interrotto) che causa l' Page.IsPostBackessere false(che uccide lo stato all'interno del mio limite controlli). Ho trovato che il colpevole era il metodo live (). Mi rendo conto che il primo postback verrà interrotto da UpdatePanel per specifica, ma solo se ce n'è un altro nella coda di cui non esiste.
timmi4sa,

20

Puoi anche provare:

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

, poiché pageLoad () è un evento ajax ASP.NET che viene eseguito ogni volta che la pagina viene caricata sul lato client.


pageLoad duplica gli eventi su ogni postback ASync del pannello di aggiornamento.
Zo ha il

17

La mia risposta?

function pageLoad() {

  $(document).ready(function(){

eccetera.

Ha funzionato come un incantesimo, dove diverse altre soluzioni hanno fallito miseramente.


Perfetto per ridimensionare le aree di testo nella mia visualizzazione elenco nel mio UpdatePanel nel mio controllo utente in base alla quantità di testo.
Risorsa

Ho faticato a far funzionare correttamente le funzioni dom jquery sul postback con i pannelli di aggiornamento, questa soluzione ha funzionato e non ho dovuto duplicare le mie chiamate di funzione in 2 scenari. Ciò ha reso disponibili le funzioni jquery e l'ascoltatore. Nota ho inserito tutte le mie librerie di script e jquery proprio prima del tag FORM [end] nella parte inferiore della pagina. Grazie!!!
moto_geek

7

Vorrei utilizzare uno dei seguenti approcci:

  1. Incapsula il binding di eventi in una funzione ed eseguilo ogni volta che aggiorni la pagina. È sempre possibile contenere l'evento che si associa a elementi specifici in modo da non associare più eventi agli stessi elementi.

  2. Usa il plug-in livequery , che praticamente esegue il metodo uno per te in modo automatico. Le tue preferenze possono variare a seconda della quantità di controllo che desideri avere sul binding dell'evento.


7

Questo ha funzionato per me:

$(document).ready(function() {

    // Do something exciting

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

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

});

6

La funzione pageLoad () è molto pericolosa da utilizzare in questa situazione. È possibile che gli eventi vengano collegati più volte. Vorrei anche stare lontano da .live () in quanto si collega all'elemento del documento e deve attraversare l'intera pagina (lenta e scadente).

La migliore soluzione che ho visto finora è usare la funzione jQuery .delegate () su un wrapper esterno al pannello di aggiornamento e fare uso del gorgogliamento. Oltre a ciò, puoi sempre collegare i gestori utilizzando la libreria Ajax di Microsoft, progettata per funzionare con UpdatePanels.


6

Quando $(document).ready(function (){...})non funziona dopo il post della pagina, utilizza la funzione JavaScript pageLoad in Asp.page come segue:

<script type="text/javascript" language="javascript">
function pageLoad() {
// Initialization code here, meant to run once. 
}
</script>

Sì, verificare la presenza di isPartialLoad così: stackoverflow.com/questions/301473/...
Steve Greene

4

Ho avuto un problema simile e ho scoperto che il modo migliore per farlo era affidarmi al gorgogliamento degli eventi e alla delega degli eventi per gestirlo. La cosa bella della delega di eventi è che una volta installato, non è necessario ricollegare gli eventi dopo un aggiornamento AJAX.

Quello che faccio nel mio codice è impostare un delegato sull'elemento padre del pannello di aggiornamento. Questo elemento padre non viene sostituito in un aggiornamento e pertanto l'associazione di eventi non viene interessata.

Esistono numerosi buoni articoli e plug-in per gestire la delega degli eventi in jQuery e la funzione verrà probabilmente inserita nella versione 1.3. L'articolo / plugin che uso come riferimento è:

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

Una volta capito cosa sta succedendo, penso che troverai una soluzione molto più elegante che è più affidabile del ricordare di ricollegare gli eventi dopo ogni aggiornamento. Ciò ha anche l'ulteriore vantaggio di offrirti un evento per separarti quando la pagina viene scaricata.


4

FWIW, ho riscontrato un problema simile con i mootools. Ricollegare i miei eventi è stata la mossa corretta, ma doveva essere eseguita alla fine della richiesta

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

Solo qualcosa da tenere a mente se beginRequest ti fa ottenere eccezioni JS di riferimento null.

Saluti



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

La funzione pageLoad è perfetta per questo caso poiché viene eseguita sul caricamento della pagina iniziale e su ogni postback asincrono di updatepanel. Ho dovuto solo aggiungere il metodo unbind per far funzionare jquery sui postback di updatepanel.

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


2

La mia risposta si basa su tutti i commenti degli esperti sopra, ma sotto è il seguente codice che chiunque può usare per assicurarsi che su ogni postback e su ogni postback asincrono il codice JavaScript verrà comunque eseguito.

Nel mio caso, avevo un controllo utente all'interno di una pagina. Basta incollare il codice seguente nel controllo utente.

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

2

Il pannello di aggiornamento sostituisce sempre Jquery con gli script di Scriptmanager integrati dopo ogni caricamento. È meglio se usi i metodi di istanza di pageRequestManager come questo ...

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

funzionerà benissimo ...


Un vecchio post, ma uno che mi ha aiutato. Una cosa che vorrei aggiungere a questo: la posizione del codice add_endRequest deve trovarsi all'interno di UpdatePanel, poiché Sys.WebForms.PageRequestManager è disponibile solo a quel punto. Tuttavia, la funzione effettiva non deve trovarsi in quella posizione. Quindi, nel mio caso, ho un file script.js che contiene il codice che voglio associato, contenuto in una funzione. In quel file script.js, ho una chiamata document.ready, che richiama la funzione sopra. Quindi, nel mio UpdatePanel, ho il codice add_endRequest, che invoca anche la funzione sopra.
Kiran Ramaswamy il

1

Usa lo script seguente e modifica il corpo dello script di conseguenza.

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

0

In risposta alla risposta di Brian MacKay:

Inietto JavaScript nella mia pagina tramite ScriptManager invece di inserirlo direttamente nel codice HTML di UserControl. Nel mio caso, devo scorrere fino a un modulo reso visibile dopo che UpdatePanel è terminato e restituito. Questo va nel codice dietro il file. Nel mio esempio, ho già creato la variabile prm nella pagina del contenuto principale.

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

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
        });
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.