web-dev-qa-db-ja.com

jQuery $(document).readyとUpdatePanels?

私はjQueryを使ってUpdatePanelの中​​にある要素にマウスオーバー効果をもたらします。イベントは$(document).readyにバインドされています。例えば:

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

もちろん、これはページが最初にロードされたときにはうまく機能しますが、UpdatePanelが部分的なページ更新を行うと、それは実行されず、マウスオーバー効果はUpdatePanel内ではこれ以上機能しません。

最初のページの読み込み時だけでなく、UpdatePanelが部分的なページ更新を起動するたびにjQueryに配線するための推奨されるアプローチは何ですか? $(document).readyの代わりにASP.NET ajaxライフサイクルを使うべきですか?

466
Herb Caudill

UpdatePanelは、更新時に更新パネルの内容を完全に置き換えます。つまり、更新パネルに新しい要素が追加されたため、あなたが購読していたイベントは購読されなくなりました。

これを回避するために私がしたのは、更新のたびに必要なイベントを再購読することです。私は最初のロードに$(document).ready()を使い、それからMicrosoftのPageRequestManager(あなたのページに更新パネルがあるなら利用可能です)を使ってすべての更新を再購読します。

$(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は、更新パネルがページ上にある場合に自動的に利用可能になるjavascriptオブジェクトです。 UpdatePanelがページ上にある限り、それを使用するために上記のコード以外のことをする必要はありません。

より詳細な制御が必要な場合は、このイベントは.NETイベントに引数(sender, eventArgs)を渡すのと同じように引数を渡すので、イベントの発生原因を確認し、必要に応じて再バインドすることができます。

これがマイクロソフトからのドキュメントの最新版です: msdn.Microsoft.com/.../bb383810.aspx


あなたのニーズによっては、jQueryの .on() を使うのが良い方法です。これらの方法は、更新のたびにDOM要素を再購読するよりも効率的です。ただし、この方法を使用する前にすべての資料をお読みください。これは、ニーズを満たすかどうかにかかわらず可能です。 .delegate().on()を使うことをリファクタリングするのが不合理となることが多くのjQueryプラグインがあるので、そのような場合は、再購読するほうが賢明です。

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

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

更新される予定のエリア。

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

UpdatePanel内でjQueryを使用したユーザーコントロール

これは質問に対する直接的な答えではありませんが、ここで見つけた答えを読んでこの解決策をまとめました。

ユーザーコントロール内でjQuery textareaリミッターを使用しようとしていました。ユーザーコントロールはUpdatePanel内で実行され、コールバック時にバインディングを失うため、これは注意が必要です。

これが単なるページであれば、ここでの答えは直接当てはまります。ただし、ユーザーコントロールはheadタグに直接アクセスすることも、UpdatePanelに直接アクセスすることもありませんでした。

このスクリプトブロックをユーザーコントロールのマークアップの一番上に配置しました。最初のバインドでは、$(document).readyを使用し、そこから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>

だから...ちょうど誰かがこれがうまくいくことを知りたいと思うかもしれないと思った。

62
Brian MacKay

JQuery 1.3にアップグレードして、

$(function() {

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

});

注意:liveはほとんどのイベントで動作しますが、すべてではありません。完全なリストは ドキュメント にあります。

33
svinto

あなたも試すことができます:

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

pageLoad()はASP.NETのajaxイベントなので、クライアント側でページが読み込まれるたびに実行されます。

20
Daniel Hursan

私の答え?

function pageLoad() {

  $(document).ready(function(){

等.

他の解決策の多くが悲惨に失敗した魅力のように働きました。

16
Jono

これは私のために働いた:

$(document).ready(function() {

    // Do something exciting

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

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

});
7
Turbojohan

次のいずれかの方法を使用します。

  1. イベントバインディングを関数にカプセル化し、ページを更新するたびにそれを実行します。イベントを同じ要素に複数回バインドしないように、常に特定の要素へのイベントのバインドを含めることができます。

  2. livequery プラグインを使用します。これは基本的に自動的に方法1を実行します。あなたの好みはあなたがイベントバインディングに対してあなたが望むコントロールの量によって変わるかもしれません。

7
Eran Galperin

ページのポストバック後に$(document).ready(function (){...})が機能しない場合は、Asp.pageのJavaScript関数pageLoadを次のように使用します。

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

この状況では、pageLoad()関数を使用するのは非常に危険です。あなたはイベントが複数回有線になる可能性があります。 .live()はドキュメント要素に添付されていて、ページ全体を移動する必要があるため、私はまた遠ざかるでしょう(遅くてぎこちない)。

私がこれまで見た中で最高の解決策は、アップデートパネルの外側のラッパーでjQueryの.delegate()関数を使用し、バブリングを利用することです。それ以外の場合は、UpdatePanelsと連携するように設計されたMicrosoftのAjaxライブラリを使用して、常にハンドラを関連付けることができます。

6
Norm

それにもかかわらず、私はmootoolsで同様の問題を経験しました。私のイベントを再添付することは正しい動きでした、しかし要求の終わりにされる必要がありました..例

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

BeginRequestが原因でnull参照のJS例外が発生する場合に注意する必要があります。

乾杯

4
SanjayU

これはアップデートパネルで使用するための素晴らしいプラグインです。

http://updatepanelplugin.codeplex.com/

4
A_Surtees

私は同じような問題を抱えていて、それを処理するためにイベントバブリングとイベント委任に頼ることが最もうまくいった方法を見つけました。イベントの委任について素晴らしいのは、一度設定すれば、AJAX更新後にイベントを再バインドする必要がないということです。

私のコードで私がすることは更新パネルの親要素にデリゲートを設定することです。この親要素は更新時に置き換えられないため、イベントバインディングは影響を受けません。

JQueryにはイベントの委任を処理するための優れた記事とプラグインが多数あり、その機能はおそらく1.3リリースに組み込まれるでしょう。私が参考にする記事/プラグインは、次のとおりです。

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

何が起こっているのか理解できたら、更新のたびにイベントを再バインドすることを忘れずに信頼できる、はるかに洗練された解決策が見つかると思います。これには、ページがアンロードされたときにアンバインドするイベントを1つ与えるという追加の利点もあります。

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

PageLoad関数は、最初のページロードとすべてのupdatepanel非同期ポストバックで実行されるため、この場合に最適です。私はちょうどjqueryがupdatepanelポストバックで機能するようにunbindメソッドを追加する必要がありました。

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

3
Duane

私の答えは上記のすべての専門家のコメントに基づいていますが、以下のコードは、各ポストバックおよび各非同期ポストバックでJavaScriptコードが実行されることを確認するために使用できる以下のコードです。

私の場合は、ページ内にユーザーコントロールがありました。以下のコードをユーザーコントロールに貼り付けるだけです。

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

更新パネルは、毎回の読み込み後、常にあなたのJqueryを作り付けのScriptmanagerのスクリプトに置き換えます。あなたがこのようなpageRequestManagerのインスタンスメソッドを使用するならばそれはより良いです...

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

それはうまくいくでしょう...

2
Rohit Sharma

Brian MacKayの答えに答えて:

JavaScriptをUserControlのHTMLに直接配置するのではなく、ScriptManagerを介して自分のページに挿入します。私の場合は、UpdatePanelが終了して戻った後に表示されるフォームにスクロールする必要があります。これはファイルの背後にあるコードで行われます。私のサンプルでは、​​メインコンテンツページでprm変数を作成しました。

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

以下のスクリプトを使用して、それに応じてスクリプトの本文を変更してください。

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