jQuery $ (документ) .ready и UpdatePanels?

474

Я использую jQuery для подключения некоторых эффектов mouseover к элементам, находящимся внутри UpdatePanel. События связаны в $(document).ready. Например:

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

Конечно, это работает при первом загрузке страницы, но когда UpdatePanel выполняет частичное обновление страницы, оно не запускается и эффекты mouseover больше не работают внутри UpdatePanel.

Какой рекомендуемый подход для подключения в jQuery не только к загрузке первой страницы, но и каждый раз, когда UpdatePanel запускает частичное обновление страницы? Должен ли я использовать жизненный цикл ajax ASP.NET вместо $(document).ready?

Теги:
javascript-events
asp.net-ajax

19 ответов

522
Лучший ответ

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), чтобы вы могли видеть, что подняло событие и только переустанавливать при необходимости.

Ниже приведена последняя версия документации Microsoft: msdn.microsoft.com/.../bb383810.aspx


В зависимости от ваших потребностей лучше использовать jQuery .on(). Эти методы более эффективны, чем повторная подписка на элементы DOM при каждом обновлении. Прочитайте всю документацию, прежде чем использовать этот подход, поскольку он может или не может удовлетворить ваши потребности. Существует много плагинов jQuery, которые были бы необоснованными для рефакторинга для использования .delegate() или .on(), поэтому в этих случаях вам лучше переподписываться.

  • 1
    Пожалуйста, будьте более точны, когда вы даете объяснение. Я имею в виду пример использования гораздо лучше, чем пара разбросанных строк кода. См. Объяснение Брайана Маккея. Это идеально!
  • 3
    @Dan, Начиная с jQuery 1.7, .delegate() был заменен на .on()
Показать ещё 6 комментариев
158
<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>
  • 0
    Хорошо работает для asp: GridView TextBox внутри <EditItemTemplate>
  • 0
    Проблема с этим решением заключается в том, что, хотя оно работает, оно убивает асинхронную обратную запись UpdatePanel - делая UpdatePanel снова бесполезным. (вздох)
60

Пользовательский элемент управления с помощью jQuery внутри UpdatePanel

Это не прямой ответ на вопрос, но я собрал это решение, прочитав ответы, которые я нашел здесь, и я подумал, что кто-то может найти его полезным.

Я пытался использовать ограничитель текстовой области jQuery внутри пользовательского элемента управления. Это было сложно, потому что User Control запускается внутри UpdatePanel, и он терял привязки при обратном вызове.

Если это была только страница, ответы здесь были бы применены напрямую. Однако пользовательские элементы управления не имеют прямого доступа к главному тегу и не имеют прямого доступа к UpdatePanel, как предполагают некоторые из ответов.

В итоге я разместил этот блок script прямо в верхней части моей разметки User Control. Для исходного связывания он использует $(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>

Итак... Просто подумал, что кто-то может захотеть узнать, что это работает.

  • 2
    Я не мог заставить это работать на всю жизнь. Тогда я переместил это от головы до нижнего колонтитула, и это работало. Не позитивно, но я думаю, что это должно прийти после ScriptManager, который я использую.
  • 0
    В моем случае я добавлял сценарий с помощью ScriptManager.RegisterClientScriptBlock, который добавляет сценарий до определения Sys, поэтому я вместо этого использовал RegisterStartupScript (см. Здесь разницу)
Показать ещё 1 комментарий
33

Перейдите к jQuery 1.3 и используйте:

$(function() {

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

});

Примечание: live работает с большинством событий, но не со всеми. Полный список в документации.

  • 0
    Использование оперативного решения проблемы с панелями обновления. Никакие обручи не должны прыгать через.
  • 0
    Как насчет того, что должно произойти при загрузке страницы? Например зебра чередование столов? $ ('TABLE TR: nth-child (odd)'). AddClass ('alt-row');
Показать ещё 2 комментария
19

Вы также можете попробовать:

<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() - это событие ajax для ASP.NET, которое выполняется каждый раз, когда страница загружается на стороне клиента.

  • 0
    pageLoad дублирует события на каждой обратной передаче ASync панели обновления.
16

Мой ответ?

function pageLoad() {

  $(document).ready(function(){

и др.

Работал как шарм, где ряд других решений провалился жалко.

  • 0
    Идеально подходит для изменения размера текстовых областей в моем Listview в моей UpdatePanel в моем UserControl в соответствии с объемом текста.
7

Я бы использовал один из следующих подходов:

  • Инкапсулируйте привязку события в функции и запускайте ее каждый раз при обновлении страницы. Вы всегда можете привязывать событие к определенным элементам, чтобы не связывать события несколько раз с одними и теми же элементами.

  • Используйте плагин livequery, который в основном выполняет метод один для вас автоматически. Ваши предпочтения могут различаться в зависимости от объема управления, которое вы хотите иметь при привязке события.

6

Когда $(document).ready(function (){...}) не работает после сообщения страницы, затем используйте функцию JavaScriptLoadLoad в Asp.page следующим образом:

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

Это сработало для меня:

$(document).ready(function() {

    // Do something exciting

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

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

});
5

Функция pageLoad() очень опасна для использования в этой ситуации. Возможно, события несколько раз подключались к сети. Я также должен держаться подальше от .live(), когда он прикрепляется к элементу документа и должен пересекать всю страницу (медленный и дерьмовый).

Лучшим решением, которое я видел до сих пор, является использование функции jQuery.delegate() на обертке вне панели обновлений и использование пузырьков. Кроме того, вы всегда можете подключить обработчиков с помощью библиотеки Microsoft Ajax, которая была разработана для работы с UpdatePanels.

4

Это отличный плагин для использования с панелями обновлений:

http://updatepanelplugin.codeplex.com/

4

FWIW, я столкнулся с аналогичной проблемой w/mootools. Повторное подключение моих событий было правильным шагом, но это необходимо сделать в конце запроса.

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

Просто что-то иметь в виду, если beginRequest заставляет вас получить ненужные ссылки на исключения JS.

Приветствия

4

У меня была аналогичная проблема, и я нашел способ, который лучше всего работал, - полагаться на Event Bubbling и делегирование событий для его обработки. Самое приятное в деле делегирования событий заключается в том, что после установки вам не нужно перестраивать события после обновления AJAX.

То, что я делаю в своем коде, - это установить делегат на родительский элемент панели обновления. Этот родительский элемент не заменяется при обновлении, поэтому привязка события не изменяется.

Существует множество хороших статей и плагинов для обработки делегирования событий в jQuery, и функция, скорее всего, будет испечена в версии 1.3. Статья/плагин, который я использую для ссылки:

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

Как только вы поймете, что это происходит, я думаю, вы найдете это гораздо более элегантное решение, которое более надежно, чем напоминание о повторной привязке событий после каждого обновления. Это также имеет дополнительное преимущество - дать вам одно событие для развязки при выгрузке страницы.

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

Функция pageLoad идеально подходит для этого случая, так как она запускается при начальной загрузке страницы и в любой обратной посылке aspan. Мне просто пришлось добавить метод unbind, чтобы заставить jquery работать с postbacks updatepanel.

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

2

Панель обновления всегда заменяет ваш Jquery своими встроенными скриптами Scriptmanager после каждой загрузки. Это лучше, если вы используете методы экземпляра pageRequestManager, подобные этому...

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

он будет работать нормально...

  • 0
    Старый пост, но тот, который помог мне. Одна вещь, которую я хотел бы добавить к этому: расположение кода add_endRequest должно быть внутри UpdatePanel, так как Sys.WebForms.PageRequestManager доступен только в этой точке. Тем не менее, фактическая функция не должна быть в этом месте. Итак, в моем случае у меня есть файл script.js, который содержит код, который я хочу связать, содержащийся внутри функции. В этом файле script.js у меня есть вызов document.ready, который вызывает вышеуказанную функцию. Затем в моей UpdatePanel у меня есть код add_endRequest, который также вызывает вышеуказанную функцию.
2

Мой ответ основан на всех комментариях экспертов выше, но ниже приведен следующий код, который каждый может использовать, чтобы удостовериться в каждом обратном обращении и при каждой асинхронной обратной передаче код 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>
0

Используйте ниже сценарий и соответствующим образом измените тело сценария.

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

В ответ на ответ Брайана Маккей:

Я вставляю JavaScript на свою страницу через ScriptManager вместо того, чтобы напрямую помещать его в HTML-код UserControl. В моем случае мне нужно прокрутить до формы, которая становится видимой после завершения и возврата 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;
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню