jQuery mobile 1.1.0: strange 'pagebeforechange' behavior - jquery-mobile

I've got big HTML page with "divs" that are considered "pages" and, I'm swapping between those "divs".
I've added this code:
$(document).bind('pagebeforechange', function(e, data) {
if ( typeof data.toPage === "string" ) {
console.log(data.toPage);
}
}
And here's the console log:
#page-main
http://ba.m.p.fr/#page-panier
http://ba.m.p.fr/#page-horaires
http://ba.m.p.fr/#page-horaires&ui-page=1-5
http://ba.m.p.fr/#page-horaire-valider
So, sometimes it's only the id sometimes it's the whole URL. How comes?

I've made a workaround, this is not an explanation. My old code was like:
$(document).bind('pagebeforechange', function(e, data) {
if ( typeof data.toPage === "string" ) {
if (data.toPage == "page-aa" ) {
/* code for page-aa */
} else if (data.toPage === "page-bb" ) {
/* code for page-bb */
} else if (data.toPage === "page-cc" ) {
/* code for page-cc */
}
}
}
And now my new code is like this: i'm relying on 'pagebeforeshow':
$("div#page-aa").on('pagebeforeshow', function(e, data) {
/* code for page-aa */
});
$("div#page-bb").on('pagebeforeshow', function(e, data) {
/* code for page-bb */
});
$("div#page-cc").on('pagebeforeshow', function(e, data) {
/* code for page-cc */
});
And it works flawlessly. But this is a workaround, not an explanation of my question. Anyway if someone googles for that problem, and reads my question, maybe this workaround will help!

toPage can be either a jQuery collection object containing the page to be transitioned to, OR a URL reference for a page to be loaded/transitioned to.
// We only want to handle changePage() calls where the caller is
// asking us to load a page by URL.
if ( typeof data.toPage === "string" ) ...
http://jquerymobile.com/demos/1.1.1/docs/pages/page-dynamic.html

Related

How to get the newly loaded page on pageinit?

On page 1, when ajax loading to page 2, I need to get the [data-role=page] element of page 2,
but on pageinit(or pagecreate), the $.mobile.activePage is still page 1.
How to get the newly loaded page instead of the current page on pageinit?
$(document).on('pageinit', function () {
console.log($.mobile.activePage); // page 1
});
If you want to retrieve it one time only, then use pagecreate because it fires once per page and it fires before navigation is commenced.
$(document).on("pagecreate", function (e) {
if ( $(e.target).hasClass("ui-dialog") ) {
var dialog = $(e.target);
}
});
To retrieve it every time you navigate to it, you can use othe pageContainer events. In case you want to alter the page you're nacigating to, use pagecobtainerbeforechange.
$(document).on("pagecintainerbeforechange", function (e, data) {
if ( typeof data.toPage == "object" && typeof data.prevPage != "undefined" && data.toPage.hasClass("ui-dialog") ) {
data.toPage.find(".foo").addClass(".bar");
}
});
For other events in case you just want to access dialog and manipulate its markup.
$(document).on("pagecontainerbeforeshow pagecontainershow", function (e, data) {
if ( data.toPage.hasClass("ui-dialog") ) {
var dialog = data.toPage;
/* do something */
});

Unable to target ID after navigating back to first page from second page in jQuery Mobile Single Page Model

I am just beginning with jquery mobile but have experience in jquery and javascript and I seem to be experiencing difficulties with things being refreshed, not loaded, or loaded in the DOM.
Basically I have a 2 page document that have binded tap and change events to each. On both page 1 and page 2 a tap event calls the same function which is already loaded in the head of the document. I am not having issues with the function not being called yet my issue lies within the function and it appears to relate to the loaded DOM.
Here is the function:
function changeStatus(e) {
fstatus=$("#"+e).prop('title');
sID=$("#"+e).attr('rel');
if (fstatus == 'Pass') {
fstatus = 'Fail';
$("#studentColor_"+sID).css("background-color","#FCD1C5").css("border-color","#900");
$("#studentList"+sID+"_link").css("background-color","#FCD1C5");
} else if (fstatus == '') {
fstatus = 'Pass';
$("#studentColor_"+sID).css("background-color","#C5FCC5").css("border-color","#248703");
$("#studentList"+sID+"_link").css("background-color","#C5FCC5");
} else if (fstatus == 'Fail') {
fstatus = '';
$("#studentColor_"+sID).css("background-color","#FFF").css("border-color","#FFF");
$("#studentList"+sID+"_link").css("background-color","#FFF");
}
$("#studentList"+sID+"_link").prop("title",fstatus);
$("#studentColor_"+sID).prop("title",fstatus);
}
Upon entering page 1 for the first time the tap event fires as normal and all the css styles are changed correctly. Moving to page 2 the event fires however none of the css styles work, yet it sets the title correctly. Move back to page 1 and now it behaves as it did on page 2.
So from what I understand.. on initial page load of 1, page 2 is not in the DOM so $("#studentList"+sID+"_link") does not exist yet the function works completely fine. Upon moving to page 2 $("#studentList"+sID+"_link") does exist and is visible, and $("#studentColor_"+sID) which was loaded in page 1 is still in the DOM. (this is not a single page app)
Is this correct?
If the error is occurring because one of those elements don't exist anymore then wouldn't it make sense that the function would not work correctly even on the initial page load of page 1? (since the element on page 2 hasn't ever been loaded)
Also it works completely fine on a browser yet when put on mobile is when the styles stop working.
It seems that the only thing that is messing up in the function is the css() call. I hope my explanation makes sense as it baffles me..
Thanks for any help.
Additional info as requested:
It is 2 HTML documents. Both generated with a bit of php.
Here is how the elements are generated on page 1: (of course I cut out the sql calls etc)
while($row = mysql_fetch_array($result))
{
if ($row['passFail'] == '') {
$completionStatus='';
} else if ($row['passFail'] == 'P') {
$completionStatus='Pass';
} else if ($row['passFail'] == 'F') {
$completionStatus='Fail';
}
if ($completionStatus=='Pass') {
$bordercolor="#248703";
$backgroundcolor='#C5FCC5';
} else if ($completionStatus=='Fail') {
$bordercolor="#900";
$backgroundcolor='#FCD1C5';
} else if ($completionStatus == '') {
$bordercolor="#CCC";
$backgroundcolor='#FFF';
}
echo '<div class="draggable" style="text-align:center; width:50px; position:relative; font-size:.7em; top:'.$row['studentY'].'px; left:'.$row['studentX'].'px;" title="'.$completionStatus.'" rel="'.$row['ID'].'" id="student_'.$row['ID'].'"><div class="round shadow draggable_student" id="studentColor_'.$row['ID'].'" style="position: relative; background-color:'.$backgroundcolor.'; border:1px solid '.$bordercolor.'; margin-left:auto; margin-right:auto; margin-bottom:3px; width:40px; height:35px; padding:0px; font-weight:bold; text-align:center; padding-top:5px; vertical-align:middle; cursor:pointer;" title="'.$completionStatus.'"></div>'.$row[$_SESSION['student_identifier']].'</div>';
}
Here is how they are loaded into page 2:
while($row = mysql_fetch_array($result))
{
if ($row['passFail'] == '') {
$completionStatus='';
} else if ($row['passFail'] == 'P') {
$completionStatus='Pass';
} else if ($row['passFail'] == 'F') {
$completionStatus='Fail';
}
if ($completionStatus=='Pass') {
$bordercolor="#248703";
$backgroundcolor='background-color:#C5FCC5;';
} else if ($completionStatus=='Fail') {
$bordercolor="#900";
$backgroundcolor='background-color:#FCD1C5;';
} else if ($completionStatus == '') {
$bordercolor="#CCC";
$backgroundcolor='background-color:#FFF;';
}
if ($completionStatus == '') {
$readonly=' readonly';
} else {
$readonly='';
}
if ($row['asID']=='') {
$cc++;
$row['asID']=time()+$cc;
}
echo '<li><table cellpadding="0" cellspacing="0" width="100%"><tr><td class="student_infoLink" id="student'.$row['ID'].'_td" title="'.$completionStatus.'" rel="'.$row['ID'].'">'.$row['student_firstName'].' '.$row['student_lastName'].'</td><td align="right" width="10%"><input type="text" placeholder="Score" rel="'.$row['asID'].'" id="student'.$row['ID'].'_score" value="'.$row['score'].'" class="updateOnChange"'.$readonly.'><div style="padding:13px; text-align:center; display:none;"><img src="preloader.gif" width="56" height="21" border="0" /></div></td></tr></table>Edit Student</li>';
}
Please disregard all the inline styles as most will be removed once I get this fixed up.
Listeners being bound:
$(document).on('pageinit', function () {
$(function () {
function tapHandler(event) {
changeStatus($(this).attr("id"));
}
$(".student_infoLink").unbind("tap");
$(".draggable").unbind("tap");
$(".draggable").bind("tap", tapHandler);
$(".student_infoLink").bind("tap", tapHandler);
});
});
Workaround:
I am able to work around this issue with the following... by removing the call to the ID and searching off class. See below. I still would be appreciative of any help as to why the ID calls would not work. Much thanks to Omar for the help!
function changeStatus(e) {
fstatus=$(e).prop('title');
sID=$(e).attr('rel');
if (fstatus == 'Pass') {
fstatus = 'Fail';
$(e).find(".draggable_student").css("background-color","#FCD1C5").css("border-color","#900");
$("#studentList"+sID+"_link").css("background-color","#FCD1C5");
} else if (fstatus == '') {
fstatus = 'Pass';
$(e).find(".draggable_student").css("background-color","#C5FCC5").css("border-color","#248703");
$("#studentList"+sID+"_link").css("background-color","#C5FCC5");
} else if (fstatus == 'Fail') {
fstatus = '';
$(e).find(".draggable_student").css("background-color","#FFF").css("border-color","#FFF");
$("#studentList"+sID+"_link").css("background-color","#FFF");
}
$("#student"+sID+"_td").prop("title",fstatus);
$(e).prop("title",fstatus);
}
$(document).on('pageinit', function(e) {
console.log("pageinit is fired");
var pagecreated = e.target;
function tapHandler( event ){
changeStatus($(this));
}
$(".student_infoLink", pagecreated).unbind("tap");
$(".draggable", pagecreated).unbind("tap");
$(".draggable", pagecreated).bind("tap", tapHandler);
$(".student_infoLink", pagecreated).bind("tap", tapHandler);
});
I assume now that this works that the calling the ID was the issue... Any reasons why?
Quick, short answer... use classes instead of id when targeting an element. With the DOM loading multiple pages, selecting on an ID can get a bit whacky. See workaround above in edited post.

Swiping between html pages for Android app dev

I know this has been asked before but I can't get any of he examples to work.
Getting the slide transition to work where you have all the pages as separate html files seems very difficult to do? How does the next/prev part of the script know which of the other files is next?
For example, index.html should slide to 01_welcome.html - but how does it know that it's not 02_funds.html?
Thanks for any enlightenment you can give. Below is the script ( courtesy of a previous answer) I've been trying to implement.
$('div.ui-page').live("swipeleft", function () {
var nextpage = $(this).next('div[data-role="page"]');
if (nextpage.length > 0) {
$.mobile.changePage(nextpage, "slide", false, true);
}
});
$('div.ui-page').live("swiperight", function () {
var prevpage = $(this).prev('div[data-role="page"]');
if (prevpage.length > 0) {
$.mobile.changePage(prevpage, {
transition: "slide",
reverse: true
}, true, true);
}
});
The code in your OP works well in Multi-Page Model environment, since all pages (div's) are present in DOM. For Single Page Model, you will need to tweak the code a bit as each page is an individual file. Another note, .live() is deprecated, use .on() instead.
The simplest solution is to add custom attributes to each page div, e.g.
<div data-role="page" data-next-page="services" data-prev-page="about">
Retrieve the values of the custom attributes on swipe and then load the target page.
$(document).on("swipeleft swiperight", function (event) {
var activePage = $.mobile.pageContainer.pagecontainer("getActivePage"),
nextPage = activePage.data("next-page"),
prevPage = activePage.data("prev-page");
/* move to next page */
if (event.type == "swipeleft" && nextPage) {
$.mobile.pageContainer.pagecontainer("change", nextPage + ".html");
}
/* move to previous page */
if (event.type == "swiperight" && prevPage) {
$.mobile.pageContainer.pagecontainer("change", prevPage + ".html", {
reverse: true
});
}
});

jQuery Mobile - Loading External HTML

I'm loading some external html into a div in a jquery mobile app. Everything works fine, however I'm trying to make it a little bit smoother.
Here is my code:
$(document).bind('pagebeforecreate', function (event, ui) {
if (event.target.id == 'pageViewOrder') {
//get the page
$.getJSON(root_url + '/orders/view/' + window.viewOrderReference + '/?callback=?', null, function (d) {
$("#viewOrder_content").html(d.html).trigger("create");
$.mobile.loading('hide');
});
}
What's happening is the page is being displayed prior to the ajax call finishing. Is there a way of halting jquery mobile from proceeding to display the page before this call is finished? At the moment it shows the page then the content pops in.
EDIT: This is loading in single pages
Cheers,
Ben
Halting the display process is easy, you just need to call event.preventDefault().
The problem is then to make sure that you will go with the process once you retrieve your content. What I would actually do is bind to pagechange, check if you have already retrieved the data, if not, then interrupt the process, retrieve the data and start over. If yes, then proceed as planned.
var contentRetrieved = false; //will indicate wether the JSON call has already been executed
var contentToDisplay; //data from the JSON call
$(document).live('pagebeforechange', function (event, data) {
if (( typeof data.toPage === "string" ) && ($.mobile.path.parseUrl(data.toPage).hash == '#pageViewOrder')) {
if (contentRetrieved) {
contentRetrieved = false; //content is already retrieved, we proceed with the pagechange
} else {
event.preventDefault(); //prevent further page change operations
$.getJSON(root_url + '/orders/view/' + window.viewOrderReference + '/?callback=?', null, function (d) {
contentToDisplay = {"html":d.html};
contentRetrieved = true;
$.mobile.changePage("#pageViewOrder");
});
}
}
});
$(document).bind('pagebeforecreate', function (event, ui) {
if (event.target.id == 'pageViewOrder') {
$("#viewOrder_content").html(contentToDisplay.html).trigger("create");
$.mobile.loading('hide');
}
});​

PhoneGap / JQuery Mobile dbShell questions

I am trying to do a query everytime the user changes a page in a phonegap app. I am new to Phonegap/JQuery Mobile, but don't understand what is going on.
When I click a button, the pagebeforechange is getting called twice.
First time it works correctly. Next call, it does not run the dbshell.transaction, and no error is shown. So, if I click the overview page first, it works, but the other page does not. If I click the other page first, the overview page does not work. In both cases, re-visiting the same page does not re-do the query.
What's going on here? It must be something incorrect with the way I am calling dbshell?
//Listen for any attempts to call changePage().
$(document).bind( "pagebeforechange", function( e, data ) {
alert("pagebeforechange");
// We only want to handle changePage() calls where the caller is
// asking us to load a page by URL.
if ( typeof data.toPage === "string" ) {
// We are being asked to load a page by URL, but we only
// want to handle URLs that request the data for a specific
// category.
var u = $.mobile.path.parseUrl( data.toPage ),
reOverviewPage = /^#overviewPage/,
reViewByType = /^#viewByType/,
pageUrl=data.toPage;
var params = parseParams(pageUrl.substr(pageUrl.lastIndexOf("?") + 1));
if ( u.hash.search(reOverviewPage) !== -1 ) {
alert("overview");
dbShell.transaction(function(tx) {
alert("doing query");
tx.executeSql("select _id, description from area where _id=?",[params['id']],renderOverview,dbErrorHandler);
},dbErrorHandler);
} else if (u.hash.search(reViewByType) !== -1 ) {
alert("viewByType");
dbShell.transaction(function(tx) {
try
{
alert("!");
tx.executeSql("select trip.* from trip, trip_type, trip_type_lookup where trip_type.trip_id = trip._id and trip_type_lookup._id = trip_type.trip_type_lookup_id and lower(trip_type_lookup.type_name) = ?",[params['type']],dbErrorHandler, renderViewByType);
}
catch(e)
{
alert(e.message);
}
},dbErrorHandler);
}
}
});

Resources