Как я могу отложить переход страницы в jQuery Mobile, пока данные страницы не будут готовы?
У меня есть мобильное одностраничное веб-приложение, созданное с использованием jquery-mobile (jqm) и нокаута. Само приложение имеет несколько страниц, но все они содержатся в одном HTML-документе.
Проблема: после изменения "создания модели представления для страницы" с синхронизации на асинхронное поведение у меня возникает проблема, заключающаяся в том, что jquery-mobile запускает свои события до того, как данные будут готовы.
Предыстория: до недавнего времени я работал с образцами данных, в основном с огромным BLOB-объектом, и все работало гладко. С новой асинхронной композицией моделей представлений из различных источников данные не сразу готовы, и мой метод buildViewModel принимает обратный вызов продолжения вместо просто синхронного возврата данных.
Я подписываюсь на события pagebeforecreate и pagebeforechange и запускаю код, чтобы заполнить модель представления здесь. Проблема в том, что после возврата из обработчика событий jqm запускает оставшуюся цепочку событий до того, как данные станут доступны. Это вызывает переход страницы на неподготовленную страницу, что нежелательно.
Я пытался позвонить event.preventDefault
во всех предшествующих событиях и ручном вызове $.mobile.changePage, когда страница готова быть a) улучшенной и b) переход страницы происходит, но без какой-либо удачи.
Я отсканировал источник jquery-mobile, но не смог обнаружить ничего похожего на то, что позволило бы мне отложить pagebeforeshow
событие, которое по сути то, что мне нужно для того, чтобы иметь возможность правильно отобразить страницу.
Как я могу гарантировать, что 1) данные доступны и 2) нокаут был применен для выполнения начальных манипуляций с DOM, до того, как jquery-mobile попытается улучшить страницу и до того, как она выполнит переход на страницу?
Я также подумал об использовании синхронного ajax для извлечения ресурсов, но это (я думаю) не будет работать для ресурсов, загруженных с устройства (используя PhoneGap/Cordova), и имеет другие негативные последствия, которых я хотел бы избежать.
Кстати, я бы хотел избежать необходимости обрабатывать все события навигации вручную, подключая обработчики кликов повсюду, но я открыт для всех решений, если это будет необходимо.
Извиняюсь, если это дубликат; Я искал и прочитал массу вопросов, но не нашел ответа или вопроса, который был бы таким же. Просто звучит невероятно, что я бы первым решил эту проблему, так как я думаю, что это распространенный сценарий..
Обновление: уточнено описание сценария проблемы.
6 ответов
У меня была точно такая же проблема.
Единственное решение, которое мне удалось найти, - написать собственный обработчик перехода, который откладывает запуск перехода до завершения Ajax-запроса.
Вот скрипка, показывающая технику. Скрипка не использует Knockout, но показывает, как отложить переход.
В основном, так как $.ajax()
возвращает обещание, я могу передать его в обещание, возвращаемое обработчиком перехода по умолчанию, и вернуть его из моего нового обработчика.
В моем обработчике pagebeforeshow я прикрепляю обещание Ajax к странице, чтобы обработчик перехода имел к нему доступ. Не уверен, что это лучший способ, но мне понравилось больше, чем использование глобальной переменной.
Единственное, что мне не понравилось в этом, это то, что он задерживает начало перехода, пока не придет ответ Ajax, так что может показаться, что страница "зависла" от пользователя, заставляя его щелкнуть снова. Отображение сообщения о загрузке вручную делает его более отзывчивым.
Надеюсь, это поможет, и, пожалуйста, дайте мне знать, если вы найдете лучшее решение!
Задержка перехода на новую страницу до тех пор, пока ее содержимое не будет готово, является очень распространенной проблемой при работе с динамическим контентом в jQuery Mobile. Наиболее удобные способы решения этой проблемы:
Вместо классической навигации по типу href используйте ссылки на действиях "щелчка", которые сначала извлекают контент, создают новую страницу в 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) */ } } });
Установите ссылку для вызова функции загрузки вместо перехода на страницу. В вашей функции загрузки отобразите "загрузочное сообщение" и выполните вызов JSON. Наконец, в функции обратного вызова JSON измените страницу на page2
функция загрузки
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/
Обратите внимание, что если вы не хотите, чтобы пользователи могли обновлять поля ввода на странице 1 во время ожидания, введите "страницу ожидания" между страницей 1 и страницей 2, при этом инициализация "страницы ожидания" выполняется так же, как и "loadPage2",
У меня есть небольшое приложение jQuery Mobile / KnockoutJS, и я столкнулся с той же проблемой. Мое приложение содержит около 5 страниц. Все они содержатся в одном физическом HTML-документе со стандартом <div data-role="page">
разметка, разделяющая отдельные страницы.
Я наконец пошел с щелчком на основе навигации и огня $.mobile.changePage()
в результате $.ajax
успех.
Одним из недостатков этой техники является то, что вы потеряете подсветку кнопок, когда будете полагаться на onclick
против href
атрибутов. Смотрите мой пост: href vs скриптовые переходы страниц и подсветка кнопок
Позже я решил поставить оба и полагаться на href
выполнять навигацию при использовании onclick
вызывать мою логику JavaScript для загрузки ViewModels и т. д. Единственное место, где я обнаружил, что это проблема, - это когда возможная проверка требуется на исходной странице. Если это не удается, переход уже начался, а пользовательский интерфейс мигает обратно на исходную страницу. Ужасно, но это происходит только в некоторых случаях в моем приложении.
Я не думаю, что все это относится к нокауту. Мое точное решение может вызвать проблемы для вас в том, что ваша навигация может завершиться до полной загрузки вашей модели, но если вы полагаетесь на $.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
}
});
Я думаю, что вы должны снова запустить для всех виджетов, которые вы хотите связать данные из ответа на
Например, вам придется вызвать trigger
с create
или же refrest
событие для элемента$("#element").trigger('create');
JQuery Mobile будет привязывать все события по умолчанию к элементу, как он есть
--- РЕДАКТИРОВАТЬ ---
Я только что создал пример кода, я думаю, что это та же самая проблема, пожалуйста, попробуйте ссылку http://jsfiddle.net/ndkhoiits/BneqW/embedded/result/
Перед передачей данных нам нужно вызвать сервис, чтобы получить их для отображения, поэтому все события, связанные с jqm, будут удалены.
У меня есть обходной путь для этого, не заставляйте jqm запускать что-либо на элементе, мы запустим его после того, как все данные будут связаны knockoutjs. Давайте попробуем исправленную версию http://jsfiddle.net/ndkhoiits/c5a2b/embedded/result/
Вы должны поместить код перехода страницы в функцию успеха при вызове AJAX.
$.ajax({
url:"request-url",
data: data,
type: "POST",
success: function(response){
// Add Transition Code Here
}
});