web-dev-qa-db-fra.com

jQuery $ (document) .ready et UpdatePanels?

J'utilise jQuery pour connecter des effets de survol des éléments situés à l'intérieur d'un UpdatePanel. Les événements sont liés dans $(document).ready. Par exemple:

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

Bien sûr, cela fonctionne bien la première fois que la page est chargée, mais lorsque UpdatePanel effectue une mise à jour partielle de la page, elle n'est pas exécutée et les effets de survol ne fonctionnent plus dans UpdatePanel. 

Quelle est l'approche recommandée pour le câblage dans jQuery non seulement lors du chargement de la première page, mais à chaque fois qu'un UpdatePanel lance une mise à jour partielle de la page? Devrais-je utiliser le cycle de vie ajax ASP.NET au lieu de $(document).ready?

461
Herb Caudill

UpdatePanel remplace complètement le contenu du panneau de mise à jour lors d'une mise à jour. Cela signifie que les événements auxquels vous avez souscrit ne le sont plus car il y a de nouveaux éléments dans ce panneau de mise à jour.

Pour remédier à ce problème, j’ai souscrit de nouveau aux événements dont j’ai besoin après chaque mise à jour. J'utilise $(document).ready() pour le chargement initial, puis j'utilise PageRequestManager de Microsoft (disponible si vous avez un panneau de mise à jour sur votre page) pour vous réabonner à chaque mise à jour. 

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

PageRequestManager est un objet javascript qui est automatiquement disponible si un panneau de mise à jour se trouve sur la page. Vous ne devriez pas avoir besoin de faire autre chose que le code ci-dessus pour pouvoir l'utiliser tant que UpdatePanel est sur la page.

Si vous avez besoin d'un contrôle plus détaillé, cet événement transmet des arguments similaires à ceux utilisés pour les événements .NET (sender, eventArgs) afin que vous puissiez voir ce qui a été déclenché et uniquement si nécessaire.

Voici la dernière version de la documentation de Microsoft: msdn.Microsoft.com/.../bb383810.aspx


Selon vos besoins, une meilleure option consiste à utiliser la fonction .on() de jQuery. Ces méthodes sont plus efficaces que de vous réabonner aux éléments DOM à chaque mise à jour. Lisez toute la documentation avant d’utiliser cette approche, car elle peut ou non répondre à vos besoins. Il y a beaucoup de plugins jQuery qu'il serait déraisonnable de refactoriser pour utiliser .delegate() ou .on(), alors dans ce cas, vous feriez mieux de vous réabonner.

527
Dan Herbert
<script type="text/javascript">

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

La zone qui va être mise à jour.

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

Contrôle utilisateur avec jQuery à l'intérieur d'un UpdatePanel

Ce n’est pas une réponse directe à la question, mais j’ai mis cette solution en parallèle en lisant les réponses que j’ai trouvées ici, et j’ai pensé que quelqu'un pourrait la trouver utile.

J'essayais d'utiliser un limiteur jQuery textarea à l'intérieur d'un contrôle utilisateur. C'était délicat, car le contrôle utilisateur s'exécutait à l'intérieur d'un UpdatePanel et il perdait ses liaisons lors d'un rappel.

S'il ne s'agissait que d'une page, les réponses ici auraient été appliquées directement. Cependant, les contrôles utilisateur n'ont pas d'accès direct à la balise head, pas plus qu'ils n'ont un accès direct à UpdatePanel comme le supposent certaines des réponses. 

J'ai fini par placer ce bloc de script directement en haut du balisage de mon contrôle utilisateur. Pour la liaison initiale, il utilise $ (document) .ready, puis il utilise prm.add_endRequest à partir de 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>

Alors ... Je pensais que quelqu'un aimerait savoir que cela fonctionne.

62
Brian MacKay

Mettez à niveau vers jQuery 1.3 et utilisez:

$(function() {

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

});

Remarque: live fonctionne avec la plupart des événements, mais pas tous. Il existe une liste complète dans la documentation .

33
svinto

Vous pouvez aussi essayer:

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

, puisque pageLoad () est un événement ajax ASP.NET qui est exécuté chaque fois que la page est chargée côté client.

20
Daniel Hursan

Ma réponse? 

function pageLoad() {

  $(document).ready(function(){

etc.

Travaillé comme un charme, où un certain nombre d'autres solutions ont échoué lamentablement.

16
Jono

Cela a fonctionné pour moi:

$(document).ready(function() {

    // Do something exciting

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

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

});
7
Turbojohan

J'utiliserais l'une des approches suivantes:

  1. Encapsulez la liaison d'événement dans une fonction et exécutez-la chaque fois que vous mettez à jour la page. Vous pouvez toujours contenir la liaison d'événement à des éléments spécifiques afin de ne pas lier les événements plusieurs fois aux mêmes éléments.

  2. Utilisez le plug-in livequery , qui exécute fondamentalement la méthode 1 pour vous par magie. Votre préférence peut varier en fonction de la quantité de contrôle que vous souhaitez avoir sur la liaison d'événement.

7
Eran Galperin

Lorsque $(document).ready(function (){...}) ne fonctionne pas après la publication de la page, utilisez la fonction JavaScript pageLoad dans Asp.page comme suit: 

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

la fonction pageLoad () est très dangereuse à utiliser dans cette situation. Vous pouvez faire en sorte que les événements soient câblés plusieurs fois. Je resterais également à l’écart de .live () car il s’attache à l’élément document et doit parcourir toute la page (lent et merdique). 

La meilleure solution que j'ai vue jusqu'à présent consiste à utiliser la fonction jQuery .delegate () sur un wrapper en dehors du panneau de mise à jour et à utiliser le bullage. Sinon, vous pouvez toujours connecter les gestionnaires à l'aide de la bibliothèque Ajax de Microsoft, conçue pour fonctionner avec UpdatePanels. 

6
Norm

FWIW, j'ai rencontré un problème similaire avec mootools. Rattacher mes événements était le bon geste, mais devait être fait à la fin de la demande.

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

Juste quelque chose à garder à l'esprit si beginRequest vous amène à obtenir des exceptions JS de référence null.

À votre santé

4
SanjayU

C'est un excellent plug-in à utiliser avec les panneaux de mise à jour:

http://updatepanelplugin.codeplex.com/

4
A_Surtees

J'avais un problème similaire et je trouvais que la meilleure façon de fonctionner était de faire appel à Event Bubbling et à la délégation d'événements pour le gérer. La bonne chose à propos de la délégation d’événements est qu’une fois l’installation terminée, il n’est pas nécessaire de relier les événements après une mise à jour AJAX.

Ce que je fais dans mon code est d'installer un délégué sur l'élément parent du panneau de mise à jour. Cet élément parent n'est pas remplacé lors d'une mise à jour et la liaison d'événement n'est donc pas affectée.

Il existe un certain nombre de bons articles et plugins pour gérer la délégation d'événements dans jQuery et la fonctionnalité sera probablement intégrée à la version 1.3. L'article/plugin que j'utilise pour référence est:

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

Une fois que vous aurez compris ce qui se passe, je pense que vous verrez que cette solution est beaucoup plus élégante et plus fiable que de ne pas penser à relier les événements après chaque mise à jour. Cela présente également l’avantage supplémentaire de vous donner un événement à dissocier lorsque la page est déchargée.

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

La fonction pageLoad est parfaite dans ce cas car elle s’exécute au chargement initial de la page et à chaque publication asynchrone updatepanel. Je devais simplement ajouter la méthode unbind pour que jquery fonctionne avec les publications post-updatepanel.

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

3
Duane

Ma réponse est basée sur tous les commentaires d'experts ci-dessus, mais vous trouverez ci-dessous le code suivant que n'importe qui peut utiliser pour s'assurer que chaque code et chaque publication asynchrone, le code JavaScript sera toujours exécuté.

Dans mon cas, j'avais un contrôle d'utilisateur dans une page. Il suffit de coller le code ci-dessous dans votre contrôle utilisateur.

<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

Update Panel remplace toujours votre Jquery par ses scripts intégrés Scriptmanager après chaque chargement. C'est mieux si vous utilisez les méthodes d'instance de pageRequestManager comme ceci ...

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

cela fonctionnera bien ... 

2
Rohit Sharma

En réponse à la réponse de Brian MacKay:

J'injecte le code JavaScript dans ma page via le ScriptManager au lieu de le placer directement dans le code HTML de UserControl. Dans mon cas, je dois accéder à un formulaire visible une fois que UpdatePanel est terminé et renvoyé. Cela va dans le code derrière le fichier. Dans mon exemple, j'ai déjà créé la variable prm sur la page de contenu 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
fujiiface
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
        });
}
0
Tony Dong

Utilisez le script ci-dessous et modifiez le corps du script en conséquence.

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