jQuery $ (document) .ready et UpdatePanels?


475

J'utilise jQuery pour câbler des effets de survol sur des éléments qui sont à l'intérieur d'un UpdatePanel. Les événements sont liés $(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 l'UpdatePanel effectue une mise à jour partielle de la page, elle n'est pas exécutée et les effets de survol ne fonctionnent plus à l'intérieur de l'UpdatePanel.

Quelle est l'approche recommandée pour câbler des éléments dans jQuery non seulement lors du premier chargement de page, mais chaque fois qu'un UpdatePanel déclenche une mise à jour partielle de page? Dois-je utiliser le cycle de vie ajax ASP.NET à la place de $(document).ready?


Donnez à ce essayer je pense que cela va résoudre votre problème codeproject.com/Articles/21962/...
Baxterboom

Réponses:


545

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

Ce que j'ai fait pour contourner ce problème, c'est me réinscrire aux événements dont j'ai besoin après chaque mise à jour. J'utilise $(document).ready()pour le chargement initial, puis j'utilise Microsoft PageRequestManager(disponible si vous avez un panneau de mise à jour sur votre page) pour vous réinscrire à 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
});

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

Si vous avez besoin d'un contrôle plus détaillé, cet événement transmet des arguments similaires à la façon dont les événements .NET sont transmis (sender, eventArgs)afin que vous puissiez voir ce qui a déclenché l'événement et ne le relier que si nécessaire.

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


Une meilleure option que vous pourriez avoir, selon vos besoins, est d'utiliser jQuery .on(). Ces méthodes sont plus efficaces que la réabonnement aux éléments DOM à chaque mise à jour. Lisez cependant 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(), dans ces cas, vous feriez mieux de vous réinscrire.


1
Veuillez être plus précis lorsque vous donnez des explications. Je veux dire qu'un exemple d'utilisation est bien meilleur que quelques lignes de code dispersées. Voir l'explication de Brian MacKay. C'est parfait!
consulter la vérité

3
@Dan, à partir de jQuery 1.7, .delegate()a été remplacé par le.on()
Gabriele Petrioli

@ GabyakaG.Petrioli Je me rends compte qu'elle a été remplacée, mais comme cette réponse semble résoudre un problème commun, je voulais maximiser la compatibilité avec les anciennes versions de jQuery qui n'ont pas encore été mises à niveau. Ma réponse précédemment recommandée .live(...)a été officiellement déconseillée en 1.7 et pourrait être supprimée dans une future version. J'ai intentionnellement choisi .delegate()car il est pris en charge dans jQuery depuis un certain temps maintenant et ne devrait pas être supprimé de si tôt. Cependant, je mettrai à jour ma réponse pour la mentionner .on()également pour ceux qui peuvent l'utiliser.
Dan Herbert

12
Il est préférable de déclarer et de câbler le prm var à l'intérieur du $ (document) .ready, car il est possible que le Sys n'ait pas encore été déclaré (selon l'endroit où se trouve le script).
drake7707

1
@AhmedSamy Il n'est pas recommandé d'en utiliser jQuery.delegate()plus. Il a été remplacé par jQuery.on()quelle est l'API préférée à utiliser. delegate()est simplement un wrapper pour une utilisation spécifique de on(), et il est possible qu'il devienne obsolète à l'avenir. Mon commentaire précédent mentionnant a delegate()été écrit il y a plus d'un an lorsque jQuery 1.7 (qui a introduit l' on()API) a été récemment publié. Avec jQuery 1.9 déjà sorti et 2.0 en version bêta en préparation pour la sortie, c'est une bonne idée d'éviter d'utiliser delegate()dans tout nouveau code.
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>

La zone qui va être mise à jour.

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

Fonctionne bien pour asp: GridView TextBox dans <EditItemTemplate>
Dan Randolph

Le problème avec cette solution, c'est que, pendant qu'elle fonctionne, elle tue le post asynchrone du UpdatePanel - ce qui rend le UpdatePanel encore une fois inutile. (soupir)
MC9000

63

Contrôle utilisateur avec jQuery dans un UpdatePanel

Ce n'est pas une réponse directe à la question, mais j'ai mis cette solution ensemble 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 de zone de texte jQuery à l'intérieur d'un contrôle utilisateur. Cela a été délicat, car le contrôle utilisateur s'exécute à l'intérieur d'un UpdatePanel, et il perdait ses liaisons lors du rappel.

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

J'ai fini par mettre ce bloc de script 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 juste que quelqu'un aimerait savoir que cela fonctionne.


2
Je ne pouvais pas faire en sorte que cela fonctionne pour ma vie. Ensuite, je l'ai déplacé de la tête au pied de page et cela a fonctionné. Pas positif, mais je pense que cela devait venir après le ScriptManager que j'utilise.
Adam Youngers, le

Dans mon cas, j'ajoutais le script à l'aide de ScriptManager.RegisterClientScriptBlock qui ajoute le script avant que Sys ne soit défini, j'ai donc fini par utiliser RegisterStartupScript à la place (voir la différence ici )
Firas Assaad

2
Cool réponse! cela a fonctionné comme un charme dans mon application web asp.net. + pour vous
Pranesh Janarthanan

33

Mettez à niveau vers jQuery 1.3 et utilisez:

$(function() {

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

});

Remarque: fonctionne en direct avec la plupart des événements, mais pas tous. Il y a une liste complète dans la documentation .


L'utilisation de Live résout le problème avec les panneaux de mise à jour. Pas de cerceaux nécessaires pour sauter à travers.
Tim Scarborough

Qu'en est-il de quelque chose qui doit se produire sur la charge de page? Par exemple des tables à rayures zébrées? $ ('TABLEAU TR: n-enfant (impair)'). AddClass ('alt-row');
Adam Youngers, le

3
Juste pour mettre à jour, depuis jQuery 1.7, il est maintenant recommandé d'utiliser .on () à la place
George

1
Je viens de trouver un grave échec lors de l'utilisation de la live()méthode dans IE7 (projet jQuery 1.5.1 / VS2010). Lors de l'utilisation à l' live()intérieur d'un UpdatePanel dans v3.5 ASP.NET, un habitué AutoPostbackde<asp:DropDownList /> causes de 2 postbacks partielles , par opposition à 1. Le postback prévu supplémentaire émis par le navigateur n'a pas le contenu (avorté) pouvant causer des Page.IsPostBackà être false(qui tue état dans ma borne les contrôles). J'ai trouvé que le coupable était la méthode live (). Je me rends compte que la première publication doit être abandonnée par UpdatePanel par spécification, mais uniquement s'il y en a une autre dans la file d'attente, ce qui n'est pas le cas.
timmi4sa

20

Vous pouvez également 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.


pageLoad dupliquer les événements sur chaque postback ASync du panneau de mise à jour.
Zo a

17

Ma réponse?

function pageLoad() {

  $(document).ready(function(){

etc.

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


Parfait pour redimensionner les zones de texte dans ma vue de liste dans mon UpdatePanel dans mon UserControl en fonction de la quantité de texte.
Ressource

J'ai eu du mal à faire fonctionner correctement les fonctions dom jquery sur postback avec les panneaux de mise à jour, cette solution a fonctionné et je n'ai pas eu à dupliquer mes appels de fonction dans 2 scénarios. Cela a gardé les fonctions et l'écouteur jquery disponibles. Remarque Je mets tous mes scripts et ma bibliothèque jquery inclus juste avant la balise FORM [end] en bas de la page. Merci!!!
moto_geek

7

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énements à 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 essentiellement la première méthode pour vous comme par magie. Votre préférence peut varier selon la quantité de contrôle que vous souhaitez avoir sur la liaison d'événement.


7

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

});

6

La fonction pageLoad () est très dangereuse à utiliser dans cette situation. Vous pourriez avoir des événements câblés plusieurs fois. Je resterais également à l'écart de .live () car il s'attache à l'élément de document et doit parcourir toute la page (lent et merdique).

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


6

Lorsque cela $(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>

Oui, vérifiez également isPartialLoad: stackoverflow.com/questions/301473/…
Steve Greene

4

J'ai eu un problème similaire et j'ai trouvé que le moyen qui fonctionnait le mieux était de s'appuyer sur la bulle d'événements 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 la configuration effectuée, vous n'avez pas à relier les événements après une mise à jour AJAX.

Ce que je fais dans mon code, c'est configurer 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 donc la liaison d'événement n'est 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 dans 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 comprenez ce qui se passe, je pense que vous trouverez cette solution beaucoup plus élégante et plus fiable que de ne pas oublier de relier les événements après chaque mise à jour. Cela a également l'avantage supplémentaire de vous offrir un événement à dissocier lorsque la page est déchargée.


4

FWIW, j'ai rencontré un problème similaire avec mootools. Rattacher mes événements était la bonne décision, 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 fait obtenir des exceptions JS de référence null.

À votre santé



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

La fonction pageLoad est parfaite dans ce cas car elle s'exécute au chargement de page initial et à chaque publication asynchrone de updatepanel. J'ai juste dû ajouter la méthode unbind pour faire fonctionner jquery sur les publications de updatepanel.

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


2

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

Dans mon cas, j'avais un contrôle utilisateur dans une page. Collez simplement 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

Le panneau de mise à jour remplace toujours votre Jquery par ses scripts de Scriptmanager intégrés 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 ...


Un ancien poste, mais qui m'a aidé. Une chose que je voudrais ajouter à cela: l'emplacement du code add_endRequest doit être à l'intérieur de UpdatePanel, car Sys.WebForms.PageRequestManager n'est disponible qu'à ce point. Cependant, la fonction réelle n'a pas besoin d'être à cet emplacement. Donc, dans mon cas, j'ai un fichier script.js qui contient le code que je veux lié, contenu dans une fonction. Dans ce fichier script.js, j'ai un appel document.ready, qui appelle la fonction ci-dessus. Ensuite, dans mon UpdatePanel, j'ai le code add_endRequest, qui appelle également la fonction ci-dessus.
Kiran Ramaswamy

1

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

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

J'injecte le JavaScript dans ma page via le ScriptManager au lieu de le mettre directement dans le HTML du UserControl. Dans mon cas, je dois faire défiler jusqu'à un formulaire qui est rendu visible une fois le UpdatePanel terminé et retourné. 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
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
        });
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.