jQuery $ (dokument) .ready i UpdatePanels?

475

Używam jQuery, aby połączyć niektóre efekty najechania kursorem myszy na elementy znajdujące się w UpdatePanel. Wydarzenia są powiązane $(document).ready. Na przykład:

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

Oczywiście działa to dobrze przy pierwszym załadowaniu strony, ale gdy UpdatePanel wykonuje częściową aktualizację strony, nie jest uruchamiana, a efekty najechania kursorem nie działają już w UpdatePanel.

Jakie jest zalecane podejście do okablowania w jQuery nie tylko przy ładowaniu pierwszej strony, ale za każdym razem, gdy UpdatePanel uruchamia częściową aktualizację strony? Czy powinienem używać cyklu życia aukcji ASP.NET zamiast $(document).ready?

Herb Caudill
źródło
Spróbuj, myślę, że rozwiąże Twój problem codeproject.com/Articles/21962/…
Baxterboom
1
Podobne do tego pytania: stackoverflow.com/questions/301473/…
Per Hornshøj-Schierbeck

Odpowiedzi:

545

UpdatePanel całkowicie zastępuje zawartość panelu aktualizacji podczas aktualizacji. Oznacza to, że subskrybowane wydarzenia nie są już subskrybowane, ponieważ w tym panelu aktualizacji znajdują się nowe elementy.

Aby to obejść, subskrybuję wydarzenia, których potrzebuję po każdej aktualizacji. Używam $(document).ready()do początkowego ładowania, a następnie używam Microsoft PageRequestManager(dostępny, jeśli masz panel aktualizacji na swojej stronie), aby ponownie subskrybować każdą aktualizację.

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

Jest PageRequestManagerto obiekt javascript, który jest automatycznie dostępny, jeśli na stronie znajduje się panel aktualizacji. Nie powinieneś robić nic innego niż powyższy kod, aby go używać, dopóki UpdatePanel jest na stronie.

Jeśli potrzebujesz bardziej szczegółowej kontroli, to zdarzenie przekazuje argumenty podobne do argumentów przekazywanych w zdarzeniach platformy .NET, (sender, eventArgs)dzięki czemu można zobaczyć, co wywołało zdarzenie, i ponownie powiązać tylko w razie potrzeby.

Oto najnowsza wersja dokumentacji firmy Microsoft: msdn.microsoft.com/.../bb383810.aspx


Lepszą opcją, jaką możesz mieć, w zależności od potrzeb, jest użycie jQuery's .on(). Te metody są bardziej wydajne niż ponowne subskrybowanie elementów DOM przy każdej aktualizacji. Przeczytaj całą dokumentację, zanim zastosujesz to podejście, ponieważ może ono, ale nie musi, odpowiadać Twoim potrzebom. Istnieje wiele wtyczek jQuery że byłoby nierozsądne byłaby do wykorzystania .delegate()lub .on(), więc w tych przypadkach, jesteś lepiej ponownym śledzeniem.

Dan Herbert
źródło
1
Podaj wyjaśnienia, dokładniej. Mam na myśli, że przykład użycia jest znacznie lepszy niż kilka rozproszonych linii kodu. Zobacz wyjaśnienie Briana MacKaya. Jest idealny!
poszukiwacz prawdy
3
@ Dan, od jQuery 1.7, .delegate()został zastąpiony przez.on()
Gabriele Petrioli
@ GabyakaG.Petrioli Zdaję sobie sprawę, że została zastąpiona, ale ponieważ ta odpowiedź wydaje się rozwiązać typowy problem, chciałem zmaksymalizować kompatybilność ze starszymi wersjami jQuery, które nie zostały jeszcze zaktualizowane. Moja odpowiedź była wcześniej zalecana, .live(...)która została oficjalnie uznana za przestarzałą w wersji 1.7 i może zostać usunięta w przyszłej wersji. Celowo wybrałem, .delegate()ponieważ od jakiegoś czasu jest obsługiwany w jQuery i prawdopodobnie nie zostanie wkrótce usunięty. Jednak zaktualizuję swoją odpowiedź, aby wspomnieć .on()również o tych, którzy mogą z niej korzystać.
Dan Herbert,
12
Lepiej jest zadeklarować i połączyć prm var wewnątrz $ (dokumentu) .ready, ponieważ możliwe jest, że Sys nie został jeszcze zadeklarowany (w zależności od tego, gdzie jest skrypt).
drake7707
1
@AhmedSamy Nie zaleca się już używania jQuery.delegate(). Został zastąpiony przez jQuery.on()preferowany interfejs API do użycia. delegate()jest po prostu opakowaniem do określonego zastosowania on()i możliwe, że w przyszłości może stać się przestarzałe. Moja poprzednia wzmianka o komentarzu delegate()została napisana ponad rok temu, kiedy jQuery 1.7 (która wprowadziła on()API) została niedawno wydana. Ponieważ jQuery 1.9 jest już dostępny, a wersja 2.0 w wersji beta jest przygotowywana do wydania, dobrym pomysłem jest unikanie używania delegate()w nowym kodzie.
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>

Obszar, który będzie aktualizowany.

<asp:UpdatePanel...
<ContentTemplate
     <script type="text/javascript">
                    Sys.Application.add_load(BindEvents);
     </script>
 *// Staff*
</ContentTemplate>
    </asp:UpdatePanel>
Barbaros Alp
źródło
Działa dobrze dla asp: GridView TextBox wewnątrz <EditItemTemplate>
Dan Randolph
Problem z tym rozwiązaniem polega na tym, że podczas działania zabija asynchroniczny post UpdatePanel z powrotem - czyniąc UpdatePanel ponownie bezużytecznym. (westchnienie)
MC9000,
63

Kontrola użytkownika za pomocą jQuery wewnątrz UpdatePanel

To nie jest bezpośrednia odpowiedź na pytanie, ale zestawiłem to rozwiązanie, czytając odpowiedzi, które tu znalazłem, i pomyślałem, że ktoś może uznać je za przydatne.

Próbowałem użyć ogranicznika jQuery textarea wewnątrz Kontroli użytkownika. Było to trudne, ponieważ Kontrola użytkownika działa wewnątrz UpdatePanel i traciła swoje powiązania w wyniku wywołania zwrotnego.

Gdyby to była tylko strona, odpowiedzi tutaj zastosowałyby się bezpośrednio. Jednak formanty użytkownika nie mają bezpośredniego dostępu do tagu head, ani nie mają bezpośredniego dostępu do UpdatePanel, jak zakładają niektóre odpowiedzi.

W końcu umieściłem ten blok skryptu na samym początku znaczników mojej Kontroli użytkownika. Do pierwszego wiązania używa $ (dokument) .ready, a następnie używa stamtąd prm.add_endRequest:

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

Więc ... Pomyślałem, że ktoś może wiedzieć, że to działa.

Brian MacKay
źródło
2
Nie mogłem zmusić tego do pracy przez całe życie. Potem przeniosłem go z głowy do stopki i zadziałało. Nie pozytywne, ale myślę, że musiało przyjść po ScriptManager, którego używam.
Adam Youngers,
W moim przypadku dodałem skrypt za pomocą ScriptManager.RegisterClientScriptBlock, który dodaje skrypt przed zdefiniowaniem Sys, więc zamiast tego użyłem RegisterStartupScript (patrz tutaj różnica )
Firas Assaad
2
Fajna odpowiedź! działało jak urok w mojej aplikacji internetowej asp.net. + dla ciebie
Pranesh Janarthanan
33

Zaktualizuj do jQuery 1.3 i użyj:

$(function() {

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

});

Uwaga: transmisja na żywo działa z większością wydarzeń, ale nie ze wszystkimi. Dokumentacja zawiera pełną listę .

Svinto
źródło
Korzystanie z trybu na żywo rozwiązuje problem z panelami aktualizacji. Nie trzeba przeskakiwać żadnych obręczy.
Tim Scarborough
Co z czymś, co musi się wydarzyć podczas ładowania strony? Na przykład stoły z paskami zebry? $ ('TABLE TR: nth-child (nieparzysty)'). AddClass ('alt-row');
Adam Youngers,
3
Tylko do aktualizacji, ponieważ jQuery 1.7 zaleca się teraz .on () zamiast
George
1
Właśnie znalazłem poważną awarię podczas korzystania z live()metody w IE7 (projekt jQuery 1.5.1 / VS2010). Podczas używania live()wewnątrz UpdatePanel w ASP.NET v3.5 regularny AutoPostbackz <asp:DropDownList />przyczyn 2 częściowe postbacks w przeciwieństwie do oczekiwanego 1. Dodatkowa postback wydane przez przeglądarkę brakuje treści (przerwany) powodujące Page.IsPostBackbyć false(który zabija stan wewnątrz moja granica sterownica). Znalazłem winowajcą metodę live (). Zdaję sobie sprawę, że 1st postback zostanie przerwany przez UpdatePanel według specyfikacji, ale tylko wtedy, gdy w kolejce jest inny, którego nie ma.
timmi4sa
20

Możesz także spróbować:

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

, ponieważ pageLoad () to zdarzenie ajaxowe ASP.NET, które jest wykonywane za każdym razem, gdy strona jest ładowana po stronie klienta.

Daniel Hursan
źródło
pageLoad duplikuje zdarzenia przy każdym opóźnieniu zwrotnym ASync w panelu aktualizacji.
Zo ma
17

Moja odpowiedź?

function pageLoad() {

  $(document).ready(function(){

itp.

Działał jak urok, w którym wiele innych rozwiązań zawiodło.

Jono
źródło
Idealny do zmiany rozmiaru obszarów tekstowych w moim widoku listy w moim UpdatePanel w moim UserControl zgodnie z ilością tekstu.
Zasoby
Walczyłem o to, aby funkcje JQuery Dom działały poprawnie na postback z panelami aktualizacji, to rozwiązanie działało i nie musiałem powielać moich wywołań funkcji w 2 scenariuszach. Dzięki temu funkcje jquery i detektor były dostępne. Uwaga: Umieszczam całą moją bibliotekę skryptów i jquery tuż przed znacznikiem FORM [end] na dole strony. Dzięki!!!
moto_geek
7

Chciałbym zastosować jedno z następujących podejść:

  1. Hermetyzuj powiązanie zdarzenia w funkcji i uruchamiaj je przy każdej aktualizacji strony. Zawsze możesz zawierać powiązanie zdarzenia z określonymi elementami, aby nie wiązać zdarzeń wiele razy z tymi samymi elementami.

  2. Skorzystaj z wtyczki livequery , która w zasadzie wykonuje dla Ciebie metodę pierwszą automatycznie. Twoje preferencje mogą się różnić w zależności od stopnia kontroli powiązania zdarzenia.

Eran Galperin
źródło
7

To działało dla mnie:

$(document).ready(function() {

    // Do something exciting

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

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

});
Turbojohan
źródło
6

W tej sytuacji bardzo niebezpieczne jest użycie funkcji pageLoad (). Możliwe, że wydarzenia zostaną połączone wielokrotnie. Byłbym również z dala od .live (), ponieważ dołącza się do elementu dokumentu i musi przeglądać całą stronę (powolną i kiepską).

Najlepszym rozwiązaniem, jakie do tej pory widziałem, jest użycie funkcji jQuery .delegate () na opakowaniu poza panelem aktualizacji i korzystanie z propagacji. Poza tym zawsze można było połączyć programy obsługi za pomocą biblioteki Ajax firmy Microsoft, która została zaprojektowana do pracy z UpdatePanels.

Norma
źródło
6

Jeśli $(document).ready(function (){...})nie działa po opublikowaniu strony, użyj funkcji JavaScript pageLoad w Asp.page w następujący sposób:

<script type="text/javascript" language="javascript">
function pageLoad() {
// Initialization code here, meant to run once. 
}
</script>
Pradeep More
źródło
Tak, sprawdź również isPartialLoad: stackoverflow.com/questions/301473/...
Steve Greene
4

Miałem podobny problem i odkryłem, że najlepszym sposobem było poleganie na Event Bubbling i delegowaniu wydarzeń, aby sobie z tym poradzić. Zaletą delegowania zdarzeń jest to, że po skonfigurowaniu nie trzeba ponownie łączyć zdarzeń po aktualizacji AJAX.

To, co robię w kodzie, to ustawienie delegata na elemencie nadrzędnym panelu aktualizacji. Ten element nadrzędny nie jest zastępowany podczas aktualizacji, a zatem powiązanie zdarzenia pozostaje nienaruszone.

Istnieje wiele dobrych artykułów i wtyczek do obsługi delegowania zdarzeń w jQuery, a funkcja prawdopodobnie zostanie upieczona w wersji 1.3. Artykuł / wtyczka, której używam w celach informacyjnych to:

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

Kiedy zrozumiesz, co się dzieje, myślę, że znajdziesz to o wiele bardziej eleganckie rozwiązanie, bardziej niezawodne niż pamiętanie o ponownym wiązaniu zdarzeń po każdej aktualizacji. Ma to również tę dodatkową zaletę, że daje jedno zdarzenie do oderwania, gdy strona jest rozładowana.

Joe Brinkman
źródło
4

FWIW, doświadczyłem podobnego problemu z mootools. Ponowne dołączenie moich zdarzeń było poprawnym ruchem, ale musiało zostać wykonane na końcu żądania. Np

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

Należy tylko pamiętać, jeśli parametr beginRequest powoduje uzyskanie wyjątków JS o zerowej wartości referencyjnej.

Twoje zdrowie


źródło
3
pageLoad = function () {
    $('#div').unbind();
    //jquery here
}

Funkcja pageLoad jest idealna w tym przypadku, ponieważ działa przy początkowym ładowaniu strony i każdym ponownym asynchronicznym ponownym ładowaniu strony. Musiałem tylko dodać metodę unbind, aby jquery działało na postbackpanach updatepanel.

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

Duane
źródło
2

Moja odpowiedź opiera się na wszystkich powyższych komentarzach ekspertów, ale poniżej znajduje się następujący kod, którego każdy może użyć, aby upewnić się, że przy każdym postback i przy każdym asynchronicznym postback kod JavaScript będzie nadal wykonywany.

W moim przypadku miałem kontrolę użytkownika na stronie. Po prostu wklej poniższy kod do swojej kontroli użytkownika.

<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
źródło
2

Panel aktualizacji zawsze zastępuje twoją Jquery wbudowanymi skryptami Scriptmanager po każdym załadowaniu. Lepiej jest, jeśli używasz takich metod instancji pageRequestManager ...

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

będzie dobrze działać ...

Rohit Sharma
źródło
Stary post, ale taki, który mi pomógł. Jedną rzecz, którą chciałbym do tego dodać: lokalizacja kodu add_endRequest musi znajdować się wewnątrz UpdatePanel, ponieważ Sys.WebForms.PageRequestManager jest dostępny tylko w tym momencie. Jednak faktyczna funkcja nie musi znajdować się w tym miejscu. Tak więc w moim przypadku mam plik script.js, który zawiera kod, który chcę powiązać, zawarty w funkcji. W tym pliku script.js mam wywołanie document.ready, które wywołuje powyższą funkcję. Następnie w moim UpdatePanel mam kod add_endRequest, który również wywołuje powyższą funkcję.
Kiran Ramaswamy
1

Użyj poniższego skryptu i odpowiednio zmień jego treść.

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

W odpowiedzi na odpowiedź Briana MacKaya:

Wprowadzam JavaScript do mojej strony za pomocą ScriptManager zamiast umieszczać go bezpośrednio w kodzie HTML UserControl. W moim przypadku muszę przewinąć do formularza, który jest widoczny po zakończeniu i zwróceniu UpdatePanel. To znajduje się w kodzie pliku. W moim przykładzie utworzyłem już zmienną prm na głównej stronie treści.

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
źródło
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
źródło