jQuery $(документ).ready и UpdatePanels?
Я использую jQuery для подключения некоторых эффектов наведения мыши на элементах внутри UpdatePanel. События связаны в $(document).ready
, Например:
$(function() {
$('div._Foo').bind("mouseover", function(e) {
// Do something exciting
});
});
Конечно, это работает нормально при первой загрузке страницы, но когда UpdatePanel выполняет частичное обновление страницы, он не запускается и эффекты наведения мыши больше не работают внутри UpdatePanel.
Каков рекомендуемый подход для подключения компонентов в jQuery не только при первой загрузке страницы, но и каждый раз, когда UpdatePanel запускает частичное обновление страницы? Должен ли я использовать жизненный цикл ASP.NET ajax вместо $(document).ready
?
20 ответов
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, который автоматически доступен, если на странице есть панель обновления. Вам не нужно делать ничего, кроме приведенного выше кода, чтобы использовать его, пока панель обновления находится на странице.
Если вам нужен более подробный контроль, это событие передает аргументы, аналогичные тому, как события.NET передаются аргументы (sender, eventArgs)
так что вы можете увидеть, что вызвало событие, и только повторно связать, если это необходимо.
Вот последняя версия документации от Microsoft: http://msdn.microsoft.com/en-us/library/bb383810.aspx
Лучший вариант, который вы можете иметь, в зависимости от ваших потребностей, это использовать jQuery's .on()
, Эти методы более эффективны, чем повторная подписка на элементы DOM при каждом обновлении. Однако, прежде чем использовать этот подход, прочитайте всю документацию, поскольку она может соответствовать или не соответствовать вашим потребностям. Существует множество плагинов jQuery, которые было бы неразумно использовать для рефакторинга. .delegate()
или же .on()
так что в этих случаях вам лучше переподписаться.
<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>
Пользовательский элемент управления с jQuery внутри UpdatePanel
Это не прямой ответ на вопрос, но я соединил это решение, прочитав ответы, которые нашел здесь, и подумал, что кто-то может найти его полезным.
Я пытался использовать ограничитель текстовой области jQuery внутри пользовательского элемента управления. Это было сложно, потому что пользовательский элемент управления работает внутри 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>
Так что... Просто подумал, что кто-то хотел бы знать, что это работает.
Обновитесь до jQuery 1.3 и используйте:
$(function() {
$('div._Foo').live("mouseover", function(e) {
// Do something exciting
});
});
Примечание: live работает с большинством событий, но не со всеми. Полный список в документации.
Вы также можете попробовать:
<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, которое выполняется каждый раз, когда страница загружается на стороне клиента.
Мой ответ?
function pageLoad() {
$(document).ready(function(){
и т.п.
Работал как шарм, где ряд других решений с треском провалились.
Я бы использовал один из следующих подходов:
Инкапсулируйте привязку события в функцию и запускайте ее каждый раз, когда вы обновляете страницу. Вы всегда можете содержать привязку события к конкретным элементам, чтобы не связывать события несколько раз с одними и теми же элементами.
Используйте плагин livequery, который автоматически выполняет первый способ для вас. Ваше предпочтение может варьироваться в зависимости от степени контроля, который вы хотите иметь для привязки события.
Это сработало для меня:
$(document).ready(function() {
// Do something exciting
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(function() {
// re-bind your jQuery events here
});
});
Когда $(document).ready(function (){...})
не работает после пост страницы назад, затем используйте функцию JavaScript pageLoad в Asp.page следующим образом:
<script type="text/javascript" language="javascript">
function pageLoad() {
// Initialization code here, meant to run once.
}
</script>
Функция pageLoad() очень опасна для использования в этой ситуации. Вы можете сделать события проводными несколько раз. Я бы также держался подальше от.live(), так как он присоединяется к элементу документа и должен пересекать всю страницу (медленно и дрянно).
Лучшее решение, которое я видел до сих пор, - это использовать функцию jQuery .delegate() на оболочке за пределами панели обновления и использовать всплывающее окно. Кроме того, вы всегда можете подключить обработчики, используя библиотеку Microsoft Ajax, которая была разработана для работы с UpdatePanels.
У меня была похожая проблема, и я нашел способ, который работал лучше всего, - это использовать Event Bubbling и делегирование событий для ее решения. Хорошая вещь в делегировании событий заключается в том, что после настройки вам не нужно перепривязывать события после обновления AJAX.
В моем коде я настраиваю делегата на родительском элементе панели обновлений. Этот родительский элемент не заменяется при обновлении, и, следовательно, привязка события не изменяется.
Существует множество хороших статей и плагинов для обработки делегирования событий в jQuery, и эта функция, вероятно, будет включена в версию 1.3. Статья / плагин, который я использую для справки:
http://www.danwebb.net/2008/2/8/event-delegation-made-easy-in-jquery
Как только вы поймете, что происходит, я думаю, что вы найдете это гораздо более элегантное решение, более надежное, чем повторная привязка событий после каждого обновления. Это также имеет дополнительное преимущество - вы можете отменить одно событие, когда страница выгружается.
Это отличный плагин для использования с панелями обновления:
FWIW, у меня возникла похожая проблема с MooTools. Повторное присоединение моих событий было правильным ходом, но это нужно было сделать в конце запроса.. например
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(function() {...
Просто стоит иметь в виду, что beginRequest заставляет вас получать исключения JS с нулевой ссылкой.
ура
pageLoad = function () {
$('#div').unbind();
//jquery here
}
Функция pageLoad идеально подходит для этого случая, поскольку она запускается при начальной загрузке страницы и каждой асинхронной обратной передаче панели обновления. Мне просто нужно было добавить метод unbind, чтобы jquery работал с постбеками updatepanel.
http://encosia.com/document-ready-and-pageload-are-not-the-same/
Мой ответ основан на всех комментариях экспертов, приведенных выше, но ниже приведен следующий код, который любой может использовать, чтобы убедиться, что при каждой обратной передаче и при каждой асинхронной обратной передаче все еще будет выполняться код 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
});
это будет работать нормально...
Используйте скрипт ниже и измените тело скрипта соответственно.
<script>
//Re-Create for on page postbacks
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(function () {
//your codes here!
});
</script>
Для кого-либо еще в моей ситуации я пытался заставить функцию готовности документа jquery работать для DevExpress ASPxCallbackPanel, и ничего выше (на сегодняшний день) не работало. Это то, что сработало для меня.
<script>
function myDocReadyFunction(){ /* do stuff */ }
</script>
<dx:ASPxCallbackPanel ID="myCallbackPanel" ... >
<ClientSideEvents EndCallback="function(){ myDocReadyFunction();}">
</ClientSideEvents>
<PanelCollection ...>
</dx:ASPxCallbackPanel>
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
});
}
В ответ на ответ Брайана Маккея:
Я вставляю 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;
}