jQuery $ (documento) .ready e UpdatePanels?


475

Estou usando o jQuery para conectar alguns efeitos de mouseover em elementos que estão dentro de um UpdatePanel. Os eventos estão vinculados $(document).ready. Por exemplo:

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

Obviamente, isso funciona bem na primeira vez em que a página é carregada, mas quando o UpdatePanel faz uma atualização parcial da página, ela não é executada e os efeitos do mouseover não funcionam mais no UpdatePanel.

Qual é a abordagem recomendada para instalar o jQuery não apenas no carregamento da primeira página, mas sempre que um UpdatePanel dispara uma atualização parcial da página? Devo usar o ciclo de vida do ASP.NET ajax em vez de $(document).ready?


Tentar dar um presente eu acho que vai resolver o seu problema codeproject.com/Articles/21962/...
Baxterboom

Respostas:


545

Um UpdatePanel substitui completamente o conteúdo do painel de atualização em uma atualização. Isso significa que os eventos nos quais você se inscreveu não são mais inscritos porque há novos elementos nesse painel de atualização.

O que eu fiz para contornar isso é reinscrever os eventos necessários após cada atualização. Utilizo $(document).ready()o carregamento inicial e depois o da Microsoft PageRequestManager(disponível se você tiver um painel de atualização em sua página) para assinar novamente todas as atualizações.

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

O PageRequestManageré um objeto javascript que está disponível automaticamente se um painel de atualização estiver na página. Você não precisa fazer nada além do código acima para usá-lo enquanto o UpdatePanel estiver na página.

Se você precisar de um controle mais detalhado, esse evento passará argumentos semelhantes à maneira como os eventos do .NET são passados, (sender, eventArgs)para que você possa ver o que gerou o evento e somente reativar, se necessário.

Aqui está a versão mais recente da documentação da Microsoft: msdn.microsoft.com/.../bb383810.aspx


Uma opção melhor que você pode ter, dependendo de suas necessidades, é usar o jQuery .on(). Esse método é mais eficiente do que se inscrever novamente nos elementos DOM a cada atualização. Leia toda a documentação antes de usar essa abordagem, pois ela pode ou não atender às suas necessidades. Existem muitos plugins jQuery que não seriam razoáveis ​​para refatorar o uso .delegate()ou .on(), portanto, nesses casos, é melhor você se inscrever novamente.


1
Seja mais preciso quando estiver dando explicações. Quero dizer, um exemplo de uso é muito melhor do que algumas linhas de código dispersas. Veja a explicação de Brian MacKay. É perfeito!
truthseeker

3
@ Dan, a partir do jQuery 1.7, .delegate()foi substituído pelo.on()
Gabriele Petrioli

@ GabyakaG.Petrioli Sei que foi substituído, mas como essa resposta parece resolver um problema comum, eu queria maximizar a compatibilidade com versões mais antigas do jQuery que ainda não foram atualizadas. Minha resposta recomendou anteriormente, .live(...)que foi oficialmente descontinuada na versão 1.7 e pode ser removida em uma versão futura. Eu escolhi intencionalmente, .delegate()já que ele é suportado no jQuery há um tempo e provavelmente não será removido tão cedo. No entanto, atualizarei minha resposta para mencionar .on()também para aqueles que podem usá-la.
Dan Herbert

12
É melhor declarar e conectar o prm var dentro de $ (document) .ready, pois é possível que o Sys ainda não tenha sido declarado (dependendo de onde está o script).
drake7707

1
@AhmedSamy Não é mais recomendado o uso jQuery.delegate(). Foi substituída pela jQuery.on()qual é a API preferida a ser usada. delegate()é simplesmente um invólucro para um uso específico de on(), e é possível que fique obsoleto no futuro. Meu comentário anterior delegate()foi escrito há mais de um ano quando o jQuery 1.7 (que introduziu a on()API) foi lançado recentemente. Com o jQuery 1.9 já lançado e o 2.0 na versão beta sendo preparado para o lançamento, é uma boa idéia evitar o uso delegate()de qualquer novo código.
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>

A área que será atualizada.

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

Funciona bem para asp: GridView dentro de caixa de texto <EditItemTemplate>
Dan Randolph

O problema com esta solução é que, enquanto funciona, mata a postagem assíncrona do UpdatePanel - tornando o UpdatePanel inútil novamente. (suspiro)
MC9000 07/09

63

Controle de usuário com jQuery dentro de um UpdatePanel

Essa não é uma resposta direta à pergunta, mas eu montei essa solução lendo as respostas que encontrei aqui e achei que alguém poderia achar útil.

Eu estava tentando usar um limitador de área de texto jQuery dentro de um controle de usuário. Isso foi complicado, porque o Controle do Usuário é executado dentro de um UpdatePanel e estava perdendo suas ligações no retorno de chamada.

Se fosse apenas uma página, as respostas aqui seriam aplicadas diretamente. No entanto, os Controles de Usuário não têm acesso direto à tag head, nem acesso direto ao UpdatePanel, como algumas das respostas supõem.

Acabei colocando esse bloco de script na parte superior da marcação do meu Controle de Usuário. Para a ligação inicial, ele usa $ (document) .ready e, em seguida, usa prm.add_endRequest a partir daí:

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

Então ... Só pensei que alguém gostaria de saber que isso funciona.


2
Não consegui fazer isso funcionar pela minha vida. Então eu mudei da cabeça para o rodapé e funcionou. Não é positivo, mas acho que precisava vir depois do ScriptManager que estou usando.
Adam Youngers

No meu caso eu estava adicionando o script usando ScriptManager.RegisterClientScriptBlock que adiciona o script antes Sys é definido, então acabei usando RegisterStartupScript vez (ver diferença aqui )
Firas Assaad

2
Resposta legal! funcionou como um encanto no meu aplicativo da web asp.net. + para você
Pranesh Janarthanan

33

Atualize para o jQuery 1.3 e use:

$(function() {

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

});

Nota: o live funciona com a maioria dos eventos, mas não com todos. Há uma lista completa na documentação .


O uso ao vivo corrige o problema com os painéis de atualização. Não há aros necessários para pular.
22360 Tim

E algo que precisa acontecer no carregamento de página? Por exemplo, tabelas de distribuição de zebra? $ ('TABELA TR: enésimo filho (ímpar)'). AddClass ('alt-row');
Adam Youngers 08/09

3
Só para atualização, uma vez que jQuery 1.7 agora é recomendado o uso de .no () em vez
George

1
Acabei de encontrar uma falha grave ao usar o live()método no IE7 (projeto jQuery 1.5.1 / VS2010). Ao usar live()dentro de um UpdatePanel em v3.5 ASP.NET um regular AutoPostbackde <asp:DropDownList />causas 2 postbacks parciais, em oposição à 1. Espera O postback adicional emitido pelo navegador não tem o conteúdo (abortado) causando a Page.IsPostBackser false(que mata estado dentro do meu limite controles). Eu achei o culpado o método live (). Percebo que o 1º postback será abortado pelo UpdatePanel por especificação, mas apenas se houver outro na fila do qual não exista.
timmi4sa

20

Você também pode tentar:

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

, pois pageLoad () é um evento ajax do ASP.NET que é executado sempre que a página é carregada no lado do cliente.


pageLoad duplicar os eventos em cada postagem do ASync no Painel de Atualização.
perfil

17

Minha resposta?

function pageLoad() {

  $(document).ready(function(){

etc.

Funcionou como um encanto, onde várias outras soluções falharam miseravelmente.


Perfeito para redimensionar as áreas de texto no meu Listview no meu UpdatePanel no meu UserControl de acordo com a quantidade de texto.
Resource

Lutei para fazer com que as funções dom jquery funcionassem corretamente no postback com painéis de atualização, esta solução funcionou e não precisei duplicar minhas chamadas de função em dois cenários. Isso manteve as funções do jquery e o ouvinte disponíveis. Nota: Coloquei todos os meus scripts e bibliotecas jquery antes da tag FORM [end] na parte inferior da página. Obrigado!!!
moto_geek

7

Eu usaria uma das seguintes abordagens:

  1. Encapsule a associação de eventos em uma função e execute-a sempre que você atualizar a página. Você sempre pode conter a associação de eventos a elementos específicos para não associar eventos várias vezes aos mesmos elementos.

  2. Use o plug-in livequery , que basicamente executa o método um para você automaticamente. Sua preferência pode variar dependendo da quantidade de controle que você deseja ter na associação de eventos.


7

Isso funcionou para mim:

$(document).ready(function() {

    // Do something exciting

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

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

});

6

A função pageLoad () é muito perigosa para ser usada nessa situação. Você pode fazer com que os eventos sejam conectados várias vezes. Também ficaria longe de .live (), pois ele é anexado ao elemento de documento e precisa percorrer a página inteira (lenta e de baixa qualidade).

A melhor solução que eu já vi até agora é usar a função jQuery .delegate () em um invólucro fora do painel de atualização e usar bolhas. Além disso, você sempre pode conectar os manipuladores usando a biblioteca Ajax da Microsoft, projetada para funcionar com o UpdatePanels.


6

Quando $(document).ready(function (){...})não funcionar após a postagem da página, use a função JavaScript pageLoad no Asp.page da seguinte maneira:

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

Sim, verifique também o isPartialLoad: stackoverflow.com/questions/301473/…
Steve Greene

4

Tive um problema semelhante e descobri que a maneira que funcionava melhor era confiar no Bubbling de Eventos e na delegação de eventos para lidar com isso. O bom da delegação de eventos é que, uma vez configurado, você não precisa religar os eventos após uma atualização do AJAX.

O que faço no meu código é configurar um delegado no elemento pai do painel de atualização. Este elemento pai não é substituído em uma atualização e, portanto, a ligação do evento não é afetada.

Há vários bons artigos e plug-ins para lidar com a delegação de eventos no jQuery e o recurso provavelmente será inserido na versão 1.3. O artigo / plugin que eu uso para referência é:

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

Depois de entender o que está acontecendo, acho que você encontrará uma solução muito mais elegante e mais confiável do que lembrar de vincular novamente os eventos após cada atualização. Isso também tem o benefício adicional de oferecer a você um evento para desvincular quando a página é descarregada.


4

FWIW, experimentei um problema semelhante com o mootools. Voltar a anexar meus eventos foi a jogada correta, mas precisava ser feita no final da solicitação.

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

Apenas algo a ter em mente se beginRequest fizer com que você obtenha exceções de JS de referência nula.

Felicidades



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

A função pageLoad é perfeita para esse caso, pois é executada no carregamento inicial da página e em cada postagem assíncrona do updatepanel. Eu apenas tive que adicionar o método unbind para fazer o jquery funcionar nos postbacks do updatepanel.

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


2

Minha resposta é baseada em todos os comentários de especialistas acima, mas abaixo está o código a seguir que qualquer pessoa pode usar para garantir que em cada postback e em cada post assíncrono o código JavaScript ainda será executado.

No meu caso, eu tinha um controle de usuário em uma página. Basta colar o código abaixo no seu controle de usuário.

<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

O Painel de Atualização sempre substitui seu Jquery pelos scripts do seu Scriptmanager embutido após cada carregamento. É melhor se você usar os métodos de instância do pageRequestManager como este ...

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

vai funcionar bem ...


Um post antigo, mas que me ajudou. Uma coisa que eu gostaria de acrescentar a isso: a localização do código add_endRequest deve estar dentro do UpdatePanel, pois o Sys.WebForms.PageRequestManager está disponível apenas nesse momento. No entanto, a função real não precisa estar nesse local. Portanto, no meu caso, tenho um arquivo script.js que contém o código que quero vincular, contido em uma função. Nesse arquivo script.js, eu tenho uma chamada document.ready, que chama a função acima. Então, no meu UpdatePanel, tenho o código add_endRequest, que também chama a função acima.
precisa

1

Use o script abaixo e altere o corpo do script de acordo.

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

0

Em resposta à resposta de Brian MacKay:

Injeto o JavaScript na minha página por meio do ScriptManager, em vez de colocá-lo diretamente no HTML do UserControl. No meu caso, preciso rolar para um formulário que fique visível depois que o UpdatePanel for concluído e retornado. Isso vai no código por trás do arquivo. No meu exemplo, eu já criei a variável prm na página de conteúdo principal.

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
        });
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.