Как я могу отложить переход страницы в jQuery Mobile до тех пор, пока данные страницы не будут готовы?
У меня есть мобильное одностраничное веб-приложение, которое построено с использованием jquery-mobile (jqm) и нокаута. Само приложение имеет несколько страниц, но все они содержатся в одном документе HTML.
Проблема: после изменения моей модели создания модели для страницы от синхронизации до асинхронного поведения у меня возникла проблема с тем, что jquery-mobile запускает свои события до того, как данные будут готовы.
Предыстория: до недавнего времени я работал с образцами данных, в основном огромным блоком JSON, и все работало плавно. С новым асинхронным составом моделей просмотра из разных источников данные не готовы немедленно, и мой метод "buildViewModel" выполняет обратный вызов продолжения вместо просто синхронного возвращения данных.
Я подписываюсь на события pagebeforecreate и pagebeforechange и запускаю код, чтобы заполнить здесь viewmodel. Проблема в том, что после возвращения из обработчика события jqm запускает оставшуюся цепочку событий до того, как данные будут доступны. Это приводит к переходу страницы на неподготовленную страницу, что нежелательно.
Я попытался вызвать event.preventDefault
во всех предшествующих событиях и вручную вызывать $.mobile.changePage, когда страница готова быть a) улучшена, и b) переход страницы произойдет, но без везения.
Я сканировал источник jquery-mobile, но не смог обнаружить ничего похожего на то, что это позволило бы мне отложить событие pagebeforeshow
, что по сути является тем, что мне нужно, чтобы иметь возможность правильно отображать страницу.
Как я могу гарантировать, что 1) данные доступны, и 2) нокаут был применен для выполнения начальных манипуляций с DOM, прежде чем jquery-mobile попытается улучшить страницу и до того, как она выполнит переход на страницу?
Я также рассмотрел возможность использования синхронного ajax для извлечения ресурсов, но это (я думаю) не работает для ресурсов, загруженных с устройства (используя PhoneGap/Cordova), и имеет другие негативные последствия, которых я бы хотел избежать.
FWIW, я бы хотел, чтобы избежать необходимости вручную обрабатывать все события навигации, проводя вверх по всем обработчикам кликов, но при необходимости я открыт для всех решений.
Извините, если это дубликат; Я искал и читал массу вопросов, но не нашел ответа или вопроса, который был совершенно таким же. Мне просто кажется невероятным, что я первым ударил бы по этой проблеме, так как я считаю, что это распространенный сценарий.
Обновление: пояснение описания сценария проблемы.
Ответы
Ответ 1
У меня была такая же проблема.
Единственное решение, с которым я смог придумать, - написать настраиваемый обработчик перехода, который откладывает начало перехода до запроса Ajax завершается.
Здесь fiddle, показывающий технику. Скрипка не использует нокаут, но показывает, как отложить переход.
В принципе, поскольку $.ajax()
возвращает обещание, я могу передать это в обещание, возвращенное обработчиком перехода по умолчанию, и вернуть его из моего нового обработчика.
В моем обработчике pagebeforeshow я прикладываю к Ajax обещание на странице, чтобы обработчик перехода имел к нему доступ. Не уверен, что это лучший способ, но мне понравилось это лучше, чем использование глобальной переменной.
Единственное, что мне не понравилось в этом, это то, что он задерживает начало перехода до тех пор, пока не поступит ответ Ajax, так что может показаться, что страница "повесила" пользователя, чтобы он снова щелкнул. Вручную показ сообщения о загрузке заставляет чувствовать себя немного более отзывчивым.
Надеюсь, что это поможет, и, пожалуйста, дайте мне знать, если вы найдете лучшее решение!
Ответ 2
Отсрочка перехода на новую страницу до готовности ее содержимого является очень распространенной проблемой при обращении к динамическому контенту в jQuery Mobile. Наиболее удобные способы решения этой проблемы:
-
Вместо классической навигации типа href создайте ссылки на действия "click", которые сначала извлекут контент, построят новую страницу в DOM и затем начнут переход на эту новую страницу через $.mobile.changePage
. Преимущество такого подхода состоит в том, что его легко установить, недостатком является то, что вы не перемещаетесь с классическими ссылками href
-
Привязать событие pagebeforechange
на уровне документа, чтобы определить, является ли целевая страница вашей навигационной страницей на странице, содержащей динамический контент. В таком случае вы можете запретить навигацию по умолчанию, не тратьте время на создание страницы и переход на успех. Это описано в документах JQM для динамически вставляемого контента. Преимущество состоит в том, что вы все еще можете полагаться на стандартную навигацию по ссылкам href
, но для исправления и навигации по страницам требуется немного больше кода и дизайна вверх.
$(document).on( "pagebeforechange", function( e, data ) {
if ( typeof data.toPage === "string" ) {
if ( data.toPage === "myDynamicPageName" ) {
e.preventDefault(); //used to stop transition to the page (for now)
/*
Here you can make your ajax call
In you callback, once you have generated the page you can call
$.mobile.changePage
(you can pass the Div of the new page instead of its name as
the changepage parameter to avoid interrupting again the page change)
*/
}
}
});
Ответ 3
Установите ссылку, чтобы вызвать функцию загрузки, вместо перехода на страницу. В вашей функции загрузки отобразите "загрузочное сообщение" и выполните вызов JSON. Наконец, в функции обратного вызова JSON измените страницу на страницу2
функция загрузки
function loadPage2() {
/* show wait page */
$.mobile.loading( 'show', {
text: 'Loading massively huge dataset',
textVisible: true
});
/* perform JSON call then call callback */
}
Функция обратного вызова
function callback() {
$.mobile.changePage("#page2");
}
Вот рабочий JSFiddle: http://jsfiddle.net/8w7PM/
Обратите внимание, что если вы не хотите, чтобы пользователи могли обновлять поля ввода в Page 1 во время ожидания, введите "страницу ожидания" между страницами 1 и 2, при этом инициализация "страницы ожидания" выполняется так же, как "loadPage2".
Ответ 4
Думаю, вам нужно снова запустить для всего виджета, который вы хотите связать с ответом на
Например, вам нужно будет вызывать trigger
с событием create
или refrest
для элемента
$("#element").trigger('create');
JQuery Mobile свяжет все события по умолчанию с элементом, поскольку он
--- EDIT ---
Я только что создал образец кода, я думаю, что это же ваша проблема, попробуйте ссылку http://jsfiddle.net/ndkhoiits/BneqW/embedded/result/
Прежде чем разбить данные, мы должны вызвать для обслуживания, чтобы получить их для отображения, поэтому все события, привязанные jqm, будут удалены.
У меня есть обходное решение для этого, не делайте jqm fire что-либо в элементе, мы будем запускать его после того, как все данные привязаны к knockoutjs
Попробуйте исправленную версию
http://jsfiddle.net/ndkhoiits/c5a2b/embedded/result/
Это код http://jsfiddle.net/ndkhoiits/c5a2b/
Ответ 5
У меня есть небольшое приложение jQuery для мобильных устройств /KnockoutJS, и я столкнулся с той же проблемой. Мое приложение содержит около 5 страниц. Все они содержатся в одном физическом документе HTML со стандартной разметкой <div data-role="page">
, разделяющей отдельные страницы.
В результате успеха $.ajax
я, наконец, пошел с навигацией на основе кликов и пожара $.mobile.changePage()
.
Одним из недостатков этого метода является то, что вы потеряете подсветку своей кнопки, полагаясь на атрибуты onclick
vs href
. См. Мой связанный пост: href vs переходы между страницами и подсветка кнопок
Позже я решил поставить оба и полагаться на href
, чтобы выполнить навигацию, используя onclick
, чтобы вызвать мою логику JavaScript для загрузки ViewModels и т.д. Единственное место, где я обнаружил, что это проблема, - это когда возможно подтверждение на исходной странице. Если это не удается, переход уже начался, и пользовательский интерфейс снова начнет мигать на исходной странице. Ужасно, но это происходит только в ограниченном экземпляре в моем приложении.
Я не думаю, что это относится к Knockout. Мое точное решение может представить вам проблемы в том, что ваша навигация, вероятно, будет завершена до полной загрузки вашей модели, но если вы полагаетесь на $.mobile.changePage()
, все должно работать и скрывать вашу страницу до ее загрузки. Переходы должны работать нормально.
<a href="#MyNewPage" data-bind="click:LoadNewPage" data-role="button">
Load Page
</a>
$.ajax({
url: url,
cache: false,
dataType: "json",
data: requestData,
type: "POST",
async: true,
timeout: 10000,
success: function (data, textStatus, jqXHR) {
// use either href or changePage but not both
$.mobile.changePage("#NewPage");
},
error: function (jqXHR, textStatus, errorThrown) {
alert("AJAX Error. Status: " + textStatus);
// jqXHR.status
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
}
});
Ответ 6
Вы должны поместить код перехода страницы в функцию успеха при вызове AJAX.
$.ajax({
url:"request-url",
data: data,
type: "POST",
success: function(response){
// Add Transition Code Here
}
});