jQuery $ (tài liệu). yet và UpdatePanels?


475

Tôi đang sử dụng jQuery để kết nối một số hiệu ứng di chuột lên các phần tử bên trong UpdatePanel. Các sự kiện được ràng buộc trong $(document).ready. Ví dụ:

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

Tất nhiên, điều này hoạt động tốt khi lần đầu tiên trang được tải, nhưng khi UpdatePanel thực hiện cập nhật một phần trang, nó không chạy và các hiệu ứng di chuột không hoạt động nữa trong UpdatePanel.

Cách tiếp cận được đề xuất để kết nối các thứ trong jQuery không chỉ ở lần tải trang đầu tiên, mà mỗi khi UpdatePanel thực hiện cập nhật một phần trang? Tôi có nên sử dụng vòng đời ASP.NET ajax thay vì $(document).ready?


Hãy dùng thử, tôi nghĩ rằng nó sẽ giải quyết vấn đề của bạn codeproject.com/Articles/21962/iêu
Baxterboom

1
Tương tự với câu hỏi này: stackoverflow.com/questions/301473/
Kiếm

Câu trả lời:


545

UpdatePanel thay thế hoàn toàn nội dung của bảng cập nhật trên một bản cập nhật. Điều này có nghĩa là những sự kiện bạn đã đăng ký không còn được đăng ký vì có các yếu tố mới trong bảng cập nhật đó.

Những gì tôi đã làm để giải quyết vấn đề này là đăng ký lại các sự kiện tôi cần sau mỗi lần cập nhật. Tôi sử dụng $(document).ready()cho tải ban đầu, sau đó sử dụng Microsoft PageRequestManager(có sẵn nếu bạn có bảng cập nhật trên trang của mình) để đăng ký lại mỗi bản cập nhật.

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

Các PageRequestManager là một đối tượng javascript đó là tự động có sẵn nếu một bảng cập nhật là trên trang. Bạn không cần phải làm gì khác ngoài mã ở trên để sử dụng nó miễn là UpdatePanel có trên trang.

Nếu bạn cần kiểm soát chi tiết hơn, sự kiện này chuyển các đối số tương tự như cách các sự kiện .NET được truyền đối số (sender, eventArgs)để bạn có thể thấy điều gì đã nêu lên sự kiện và chỉ liên kết lại nếu cần.

Đây là phiên bản mới nhất của tài liệu từ Microsoft: msdn.microsoft.com/.../bb383810.aspx


Một tùy chọn tốt hơn mà bạn có thể có, tùy thuộc vào nhu cầu của bạn, là sử dụng jQuery .on(). Các phương pháp này hiệu quả hơn so với đăng ký lại các phần tử DOM trên mỗi bản cập nhật. Đọc tất cả các tài liệu trước khi bạn sử dụng phương pháp này, tuy nhiên, vì nó có thể hoặc không thể đáp ứng nhu cầu của bạn. Có rất nhiều plugin jQuery sẽ không hợp lý để tái cấu trúc để sử dụng .delegate()hoặc .on(), vì vậy, trong những trường hợp đó, tốt hơn hết bạn nên đăng ký lại.


1
Hãy chính xác hơn khi bạn đang đưa ra lời giải thích. Ý tôi là một ví dụ về việc sử dụng tốt hơn nhiều so với vài dòng mã rải rác. Xem lời giải thích của Brian MacKay. Thật hoàn hảo!
Truthseeker

3
@Dan, kể từ jQuery 1.7, .delegate()đã được thay thế bởi.on()
Gabriele Petrioli

@ GabyakaG.Petrioli Tôi nhận ra rằng nó đã được thay thế, nhưng vì câu trả lời này dường như giải quyết một vấn đề phổ biến, tôi muốn tối đa hóa khả năng tương thích với các phiên bản cũ hơn của jQuery chưa được nâng cấp. Câu trả lời của tôi trước đây được đề xuất .live(...)đã không còn chính thức trong 1.7 và có thể bị xóa trong phiên bản tương lai. Tôi cố tình chọn .delegate()vì nó đã được hỗ trợ trong jQuery một thời gian rồi và không có khả năng bị xóa sớm. Tuy nhiên, tôi sẽ nâng cấp câu trả lời của mình để đề cập đến .on()cho những người có thể sử dụng nó.
Dan Herbert

12
Tốt hơn là nên khai báo và kết nối var prm bên trong $ (tài liệu). Đã có, vì có thể Sys chưa được khai báo (tùy thuộc vào vị trí của tập lệnh).
Drainke7707

1
@AhmedSamy Không nên sử dụng jQuery.delegate()nữa. Nó đã được thay thế bởi jQuery.on()đó là API ưa thích để sử dụng. delegate()chỉ đơn giản là một trình bao bọc cho một mục đích sử dụng cụ thể on()và có thể nó sẽ bị phản đối trong tương lai. Việc đề cập bình luận trước đây của tôi delegate()đã được viết cách đây hơn một năm khi jQuery 1.7 (giới thiệu on()API) mới được phát hành. Với jQuery 1.9 đã sẵn sàng và 2.0 trong bản beta đã được chuẩn bị để phát hành, bạn nên tránh sử dụng delegate()bất kỳ mã mới nào.
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>

Khu vực sẽ được cập nhật.

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

Hoạt động tốt cho asp: GridView TextBox bên trong <EditItemTemplate>
Dan Randolph

Vấn đề với giải pháp này là, trong khi nó hoạt động, nó sẽ giết bài đăng không đồng bộ của UpdatePanel - làm cho UpdatePanel trở nên vô dụng một lần nữa. (thở dài)
MC9000

63

Kiểm soát người dùng với jQuery Bên trong UpdatePanel

Đây không phải là câu trả lời trực tiếp cho câu hỏi, nhưng tôi đã kết hợp giải pháp này bằng cách đọc các câu trả lời mà tôi tìm thấy ở đây và tôi nghĩ ai đó có thể thấy nó hữu ích.

Tôi đã cố gắng sử dụng một bộ giới hạn văn bản jQuery bên trong Điều khiển người dùng. Điều này thật khó khăn, bởi vì Điều khiển người dùng chạy bên trong UpdatePanel và nó đã mất các ràng buộc khi gọi lại.

Nếu đây chỉ là một trang, câu trả lời ở đây sẽ được áp dụng trực tiếp. Tuy nhiên, Kiểm soát người dùng không có quyền truy cập trực tiếp vào thẻ đầu, họ cũng không có quyền truy cập trực tiếp vào UpdatePanel như một số câu trả lời giả định.

Cuối cùng tôi đã đặt khối tập lệnh này ngay trên đầu đánh dấu Kiểm soát người dùng của tôi. Đối với liên kết ban đầu, nó sử dụng $ (tài liệu). Đã có, và sau đó nó sử dụng prm.add_endRequest từ đó:

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

Vì vậy, ... chỉ cần nghĩ rằng ai đó có thể muốn biết rằng điều này làm việc.


2
Tôi không thể có được điều này để làm việc cho cuộc sống của tôi. Sau đó, tôi chuyển nó từ đầu đến chân trang và nó hoạt động. Không tích cực, nhưng tôi nghĩ rằng nó cần phải đến sau ScriptManager mà tôi đang sử dụng.
Adam Youngers

Trong trường hợp của tôi, tôi đã thêm tập lệnh bằng ScriptManager.RegisterClientScriptBlock để thêm tập lệnh trước khi Sys được xác định, vì vậy tôi đã kết thúc bằng cách sử dụng RegisterStartupScript (xem sự khác biệt ở đây )
Firas Assaad

2
Câu trả lời tuyệt vời! nó hoạt động như một cơ duyên trong ứng dụng web asp.net của tôi. + cho bạn
Pranesh Janarthanan

33

Nâng cấp lên jQuery 1.3 và sử dụng:

$(function() {

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

});

Lưu ý: hoạt động trực tiếp với hầu hết các sự kiện, nhưng không phải tất cả. Có một danh sách đầy đủ trong tài liệu .


Sử dụng trực tiếp khắc phục sự cố với bảng cập nhật. Không có vòng cần thiết để nhảy qua.
Tim Scarborough

Điều gì về những gì cần phải xảy ra trên pageload? Ví dụ bảng sọc ngựa vằn? $ ('BẢNG TR: nth-child (lẻ)'). AddClass ('alt-row');
Adam Youngers

3
Chỉ cần cập nhật, vì jQuery 1.7 hiện được khuyến nghị sử dụng .on ()
George

1
Chỉ tìm thấy một lỗi nghiêm trọng trong khi sử dụng live()phương thức trong IE7 (dự án jQuery 1.5.1 / VS2010). Khi sử dụng live()bên trong một UpdatePanel trong v3.5 ASP.NET thường xuyên AutoPostbackcủa <asp:DropDownList />nguyên nhân 2 postbacks phần như trái ngược với mong đợi 1. postback thêm do trình duyệt thiếu nội dung (hủy bỏ) gây ra Page.IsPostBackđược false(mà giết chết tình trạng bên trong ràng buộc của tôi điều khiển). Tôi tìm thấy thủ phạm là phương thức live (). Tôi nhận ra rằng postback đầu tiên bị UpdatePanel hủy bỏ trên mỗi thông số nhưng chỉ khi có một cái khác trong hàng đợi không có.
timmi4sa

20

Bạn cũng có thể thử:

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

, vì pageLoad () là một sự kiện ASP.NET ajax được thực thi mỗi khi trang được tải ở phía máy khách.


pageLoad nhân đôi các sự kiện trên mỗi postback ASync của Update Panel.
Zo có

17

Câu trả lời của tôi?

function pageLoad() {

  $(document).ready(function(){

Vân vân.

Làm việc như một cơ duyên, nơi một số giải pháp khác thất bại thảm hại.


Hoàn hảo để thay đổi kích thước các textareas trong Listview của tôi trong UpdatePanel trong UserControl của tôi theo số lượng văn bản.
Tài nguyên

Tôi đã vật lộn để làm cho các hàm dom jquery hoạt động chính xác trên postback với bảng cập nhật, giải pháp này hoạt động và tôi không phải sao chép các lệnh gọi hàm của mình trong 2 tình huống. Điều này giữ cho các chức năng jquery và người nghe có sẵn. Lưu ý Tôi đặt tất cả tập lệnh và thư viện jquery của mình bao gồm ngay trước thẻ FORM [end] ở cuối trang. Cảm ơn!!!
moto_geek

7

Tôi sẽ sử dụng một trong những cách tiếp cận sau:

  1. Đóng gói các ràng buộc sự kiện trong một chức năng và chạy nó mỗi khi bạn cập nhật trang. Bạn luôn có thể chứa liên kết sự kiện với các thành phần cụ thể để không liên kết các sự kiện nhiều lần với cùng các yếu tố.

  2. Sử dụng các livequery plug-in, mà về cơ bản thực hiện một phương pháp cho bạn tự động một cách kỳ diệu. Tùy chọn của bạn có thể thay đổi tùy thuộc vào số lượng kiểm soát bạn muốn có trong ràng buộc sự kiện.


7

Điều này làm việc cho tôi:

$(document).ready(function() {

    // Do something exciting

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

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

});

6

hàm pageLoad () rất nguy hiểm khi sử dụng trong tình huống này. Bạn có thể có các sự kiện trở nên có dây nhiều lần. Tôi cũng sẽ tránh xa .live () vì nó gắn vào thành phần tài liệu và phải duyệt toàn bộ trang (chậm và tào lao).

Giải pháp tốt nhất tôi thấy cho đến nay là sử dụng hàm jQuery .delegate () trên một trình bao bọc bên ngoài bảng cập nhật và sử dụng bong bóng. Ngoài ra, bạn luôn có thể kết nối các trình xử lý bằng thư viện Ajax của Microsoft được thiết kế để hoạt động với UpdatePanels.


6

Khi $(document).ready(function (){...})không hoạt động sau khi đăng lại trang, hãy sử dụng chức năng JavaScript pageLoad trong Asp.page như sau:

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

Có, hãy kiểm tra isPartialLoad là tốt: stackoverflow.com/questions/301473/iêu
Steve Greene

4

Tôi đã có một vấn đề tương tự và tìm ra cách làm việc tốt nhất là dựa vào Sự kiện Bong bóng và sự kiện để xử lý nó. Điều thú vị về ủy nhiệm sự kiện là một khi thiết lập, bạn không phải khởi động lại các sự kiện sau khi cập nhật AJAX.

Những gì tôi làm trong mã của mình là thiết lập một ủy nhiệm trên phần tử cha của bảng cập nhật. Phần tử cha này không được thay thế trên một bản cập nhật và do đó ràng buộc sự kiện không bị ảnh hưởng.

Có một số bài viết và plugin tốt để xử lý ủy nhiệm sự kiện trong jQuery và tính năng này có thể sẽ được đưa vào bản phát hành 1.3. Bài viết / plugin tôi sử dụng để tham khảo là:

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

Khi bạn hiểu điều gì đang xảy ra, tôi nghĩ bạn sẽ thấy đây là một giải pháp tao nhã hơn đáng tin cậy hơn là nhớ liên kết lại các sự kiện sau mỗi lần cập nhật. Điều này cũng có thêm lợi ích là cung cấp cho bạn một sự kiện để hủy liên kết khi trang được tải.


4

FWIW, tôi đã trải qua một vấn đề tương tự w / mootools. Đính kèm lại các sự kiện của tôi là một động thái chính xác, nhưng cần phải được thực hiện vào cuối yêu cầu..eg

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

Chỉ cần một cái gì đó để ghi nhớ nếu BeginRequest khiến bạn nhận được các ngoại lệ JS tham chiếu null.

Chúc mừng



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

Hàm pageLoad hoàn hảo cho trường hợp này vì nó chạy trên tải trang ban đầu và mỗi postbackel async. Tôi chỉ cần thêm phương thức unbind để làm cho jquery hoạt động trên các postbackel updatepanel.

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


2

Câu trả lời của tôi dựa trên tất cả các ý kiến ​​chuyên gia ở trên, nhưng dưới đây là đoạn mã sau đây mà bất kỳ ai cũng có thể sử dụng để đảm bảo trên mỗi bài đăng lại và trên mỗi bài đăng lại không đồng bộ, mã JavaScript vẫn sẽ được thực thi.

Trong trường hợp của tôi, tôi có quyền kiểm soát người dùng trong một trang. Chỉ cần dán mã dưới đây trong kiểm soát người dùng của bạn.

<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

Bảng điều khiển cập nhật luôn thay thế Jquery của bạn bằng các tập lệnh Scriptmanuber sẵn có sau mỗi lần tải. Sẽ tốt hơn nếu bạn sử dụng các phương thức cá thể của pageRequestManuber như thế này ...

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

nó sẽ hoạt động tốt ...


Một bài viết cũ, nhưng một bài đã giúp tôi ra. Một điều mà tôi muốn thêm vào điều này: vị trí của mã add_endRequest phải nằm trong UpdatePanel, vì Sys.WebForms.PageRequestManager chỉ khả dụng tại thời điểm đó. Tuy nhiên, chức năng thực tế không cần phải ở vị trí đó. Vì vậy, trong trường hợp của tôi, tôi có tệp script.js chứa mã tôi muốn ràng buộc, được chứa trong một hàm. Trong tệp script.js đó, tôi có một cuộc gọi document. Yet, gọi hàm trên. Sau đó, trong UpdatePanel của tôi, tôi có mã add_endRequest, cũng gọi hàm trên.
Kiran Ramaswamy

1

Sử dụng tập lệnh bên dưới và thay đổi phần thân của tập lệnh cho phù hợp.

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

0

Đáp lại câu trả lời của Brian MacKay:

Tôi đưa JavaScript vào trang của mình thông qua ScriptManager thay vì đưa trực tiếp vào HTML của UserControl. Trong trường hợp của tôi, tôi cần cuộn đến một biểu mẫu được hiển thị sau khi UpdatePanel kết thúc và trả về. Điều này đi trong mã phía sau tập tin. Trong mẫu của tôi, tôi đã tạo biến prm trên trang nội dung chính.

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
        });
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.