How to decide which page to load first on jquery mobile? - jquery-mobile

i'm building a mobile app using jquery mobile and phonegap (Apache Cordova), the problem is that first i need to make a DB query before i decide which page i want to load first, if it's the "login" page or the "main page".
Based on the phonegap documentation i need to bind the "deviceready" event to know when the device is ready and then make the DB queries.
document.addEventListener("deviceready", onDeviceReady, false);
The function called "onDeviceReady" creates the DB if it's not created and then makes a query to a table named "users" and if there is one or more users i wan't to show a page named "main.html" otherwise a page named "login.html".
function onDeviceReady() {
var db = window.openDatabase("Database", "1.0", "Cordova Demo", 200000);
db.transaction(populateDB, errorCB, successCB);
}
Basically, the problem is that while this functions are executed the first page is loaded because the following code is executed before the "onDeviceReady" function is called:
$(document).bind( "mobileinit", function(){
$.mobile.listview.prototype.options.filterPlaceholder = "Buscar...";
//-> patch for phonegap
$.mobile.allowCrossDomainPages = true;
$.mobile.page.prototype.options.backBtnText = "atrás";
});
$( document ).bind( "pagebeforeload", function( event, data ){
// here i think i would say to phone gap not to load any page until i make the db queries
//i think i can't make the DB queries here because the "pagebeforeload" is launched before the "deviceready" function
});
If the code of the first page according to the DOM in ASC order this page is loaded:
<div data-role="page" id="page-init">
<div data-role="header" data-theme="c" data-position="fixed">
<h1>Init page</h1>
</div><!-- /header -->
</div>
If i change the page to "main.html" using $.mobile.changePage("main.html"); once i checked if there is one or more user records on the "users" table, the "page-init" page is loaded first and then the "main.html" and i don't want this because the user can se a kind of flash.
I just want decided once i checked to the "users" table which page is going to be displayed first.

I learned the following here on stackoverflow but i can't find the answer anymore so i will answer it myself:
in the end of your index:
$(document).bind("mobileinit", onMobileInit);
$(document).ready(onPageLoad);
in any JS file or script tag in index:
function onMobileInit() {
console.log("mobile init");
$.mobile.autoInitialize = false;
}
function onPageLoad() {// Document.Ready
console.log("document ready");
try {
if(someCondition) {
document.location.hash = "#profile";
} else {
document.location.hash = "#signIn";
}
} catch (exception) {
} finally {
$.mobile.initializePage();
}
}
P.S. you can put the init code somewhere else, but a loading screen would be better since it is a db call, i use the browser storage which is way way faster i think

It sounds like this can be solved with a loading screen.
Just create your first page as a loading screen then check your database and load the correct page based on the database results. You can even add the JQM spinner to tell your user that something is going on.

This question is old, however I can say that for me just assigning the hash you want to document.location.hash, for example document.location.hash = "#profile";, without the mobile initialization procedures worked fine. You need to do this before document.ready() is run.

Related

Making offline.js work with turbolinks

I am using offline.js with turbolinks and on initial page load it works fine. But if I click another links then this wont work until I refresh the page. I can see the Offline.state is down but still the view is not showing. Is there any way to manually trigger the popup window?
Update
Other than the offline.js file the only js I have is this
var
$online = $('.online'),
$offline = $('.offline');
Offline.on('confirmed-down', function () {
$online.fadeOut(function () {
$offline.fadeIn();
});
});
Offline.on('confirmed-up', function () {
$offline.fadeOut(function () {
$online.fadeIn();
});
});
This is an old question, but I ran into the same problem, maybe it can help someone.
offline.js creating these dom elements on page load inside the body HTML
<div class="offline-ui offline-ui-up">
<div class="offline-ui-content"></div>
</div>
The reason why offline.js not working after page change is that on-page change the body HTML replaced with the new content returned by the server and the code above removed.
This is how Turbolinks works, so page load will be not triggered and the offline.js dom elements will be not created.
One solution will be to warp the offline.js inside a function and call it on every page change, but it will cause eventually memory leak (as "offline" and "online" event listener will be added to 'window' on each change)
Other solution will be to save the 'offline-ui' HTML before the new page loaded and bring it back after load:
# will fire before page change and save offline.js UI
document.addEventListener("turbolinks:before-render", function() {
if (!document.offlineHtml) {
document.offlineHtml = $('.offline-ui');
}
});
# will fire afterload and will check if there is a UI to append to the body
document.addEventListener("turbolinks:load", function() {
if (document.offlineHtml) {
$(document.body).append(document.offlineHtml);
}
});
At the moment this is the best way that I could find to fix that.
This could be a turbolinks issue. In app/assets/javascripts/application.js, wrap your javascript code within:
$(document).on('turbolinks:load', function() {
// your code
});

JQM 1.4 - What is the preffered way to use pagecontainer event on a specific page/selector?

jQuery Mobile v1.4, we are february 2014.
So, I've read here (gihub) that we are supposed to make an if statement on catched pagecontainer events to assume if the page loaded is the one intended.
Here is a little scenario trying to understand the intended behavior of the new pageContainer widget and it's intended use.
Simple as that, a login page, pre-fetch a welcome page programatically, then switch to welcome page on succesful login. Welcome page have some JS script to animate the page, must be launched only when page is visible. How do we do that ?
Here are the results I got while investigating the pagecontainer events through the console. My goal here is to find a way to detect that my welcome (any page in fact) page is active/visible.
I used this format as query for the sake of understanding:
$( 'body' ).on( 'pagecontainerbeforeload', function( event, ui ) {
console.log("beforeload");
console.log(event);
console.log(ui);
});
So fresh start, when I load a page & JQM for the first time (ie. /Users/login)
Events usable :
pagecontainercreate => empty ui
PCbeforetransition => ui.toPage usable
PCshow => only get a ui.prevPage (which is empty in that case)
PCtransition => ui.toPage usable
Now, these are always launched even if you disabled the transition effects ( See api )
Ok, then I want to programatically load a page (pre-fetch it), I do : (I want /Users/welcome)
$("body").pagecontainer("load", "/Users/welcome");
I get these event launched (the page is not yet visible):
PCbeforeload => I get a url which I could use to identify the page..
PCload => pretty much the same data as PCbeforeload
All right, now I go change my page : (to /Users/welcome)
$("body").pagecontainer("change", "/Users/welcome");
I get these events triggered:
PChide => ui.nextPage is the same as a ui.toPage...
PCbeforetransition => ui.toPage usable
PCshow => only gives ui.prevPage
PCtransition => ui.toPage present as expected
Fine, now I'm pretty sure the only pagecontainer event I want to use to be sure that this page is loaded is pagecontainertransition. Here is what I implemented on every page that needs to launch JS :
Set id of the page container (PHP)
<div data-role="page" data-theme='a' id="<?php echo $this->id_url()?>">
...at the end of the page (JS)
$( 'body' ).on( 'pagecontainertransition', function( event, ui ) {
if(ui.toPage[0] == $('#'+id_url )[0] ) {
functionToLaunchWhenPageShowUp();
}
} );
Now, as you can see, I'm referring to ui.toPage 1st child [0] to compare it to $('.selector') 1st child [0] . Is that the right way to do that ? I mean, the intended way by the new API. Thanks to share your knowledge ;)
I managed to do something that works, is relatively simple, and as close I could to the DRY principle (don't repeat yourself).
In the order they are "loaded" :
JS script in < head > of document
<script type="text/javascript" src="/js/jquery-2.1.0.min.js"></script>
<script type="text/javascript">
(function(){
//Global settings for JQM 1.4.0
$( document ).on( "mobileinit", function() {
//apply overrides here
$.mobile.defaultPageTransition = 'flip';
});
// The event listener in question !
$( document ).ready(function () { //..only launched once the body exist
// The event listener in question :
$( 'body' ).on( 'pagecontainertransition', function( event, ui ) {
//gets the id you programatically give to your page
id_url = $( "body" ).pagecontainer( "getActivePage" )[0].id;
//compare the actual event data (ui.toPage)
if( ui.toPage[0] == $('#'+id_url )[0] ) {
// failsafe
if ( typeof( window[ id_url ].initPage ) === "function" ) {
// call the dynamically created init function
window[ id_url ].initPage();
}
}
} );
});
document.loadPage = function( url ){
$( "body" ).pagecontainer( "load", url , options);
};
document.changePage = function( url ){
$( "body" ).pagecontainer( "change", url , options);
};
})();
</script>
<script type="text/javascript" src="/js/jquery.mobile-1.4.0.min.js"></script>
Start of every returned page
<div data-role="page" data-theme='a' id="<?php echo $this->id_url()?>">
<div data-role="content">
<script type="text/javascript">
// we create dynamically a function named after the id you gave to that page
// this will bind it to window
this[ '<?php echo $this->id_url() ?>' ].initPage = function(){
// put anything you want here, I prefer to use a call
// to another JS function elsewhere in the code. This way I don't touch the
// settings anymore
NameOfThisPage.launchEverythingThatNeedsTo();
};
</script>
...
Here's the description for this code. First, I get one place for all those global query, JQM already forced me to put stuff in-between jquery.js & jquery.mobile.js, so let's use that.
Along with the global JQM settings, I use only one event listener bind to the body/document/(whatever it'll be in the future). It's only launched once the body exist.
Now, here's where the fun begins. I programatically give an id to every pages the server returns (namely the script route with _ instead of / ). You then create a function named after that id, it's attached to the window, (I suppose you could put it elsewhere..).
Then back to the event listener, on transition, you get that id you've set through pagecontainer( "getActivePage" ) method, use that id to grab the page jQuery style, then compare it with the data returned by the event listener.
If success, use that id to launch the init function you've putted in your page. There's a failsafe in case you don't put an init script in page.
Bonus here, are those document.loadPage / changePage . I've putted them there in case the methos to change page changes. One place to modify, and it'll apply to the entire app. That's DRY ^^
All in all, if you have comment on a way to improve this method, please share. There's a big lack of example for v1.4 methods (along with a bit of confusion with v1.3 examples). I've tried to share my discoveries the best I could (ps. I need those rep points :P )

Jquery mobile How to tap the screen to no avail

I tested on the Apple device, and when I click on the screen when there is no effect. This is my code. Click on the events of this writing there are questions?
<script>
$(function() {
$('#test').tap(function() {
$('#menuNum').text('1');
})
})
</script>
You need to change few things.
Do not use $(function() { or classic document ready to check for a correct state, they can cause problems with jQuery Mobile. Instead use jQuery Mobile alternative called page events.
Then don't bind tap event like that, use proper modern way of doing that. In your case element must be loaded into the DOM for that kind of binding to work. And because of $(function() { sometimes it can happen that element is still loading when binding is executed. So use it like this:
$(document).on('tap','#test',function() {
$('#menuNum').text('1');
});
This method don't care if element exist or not, it will even work if element is loaded into the DOM after binding process.
Working example: http://jsfiddle.net/Gajotres/SQ7DF/
In the end you want something like this:
$(document).on('pagebeforeshow', '#index', function(){
$(document).on('tap','#test',function() {
alert('Tap');
});
});

jQuery UI tabs: How do I load a specific element from a different page?

I have jQuery UI tabs set up, but a problem that I'm having with links to different pages is that they load all contents of the page into the tab. This includes the footer, header, and other navbars that I don't want in the tab. What if I would only like to load a single ID from that page?
My tabs are set up this way:
<div id="mytabs">
<ul>
<li>Awesome page</li>
<li>Foo</li>
</ul>
</div>
Nothing much going on in the jQuery...
$(function() {
$( "#mytabs" ).tabs();
});
Let's say this is the html of "awesomepage" (that the first link targets):
<html>
<head>
<title>awesome page</title>
</head>
<body>
<div id="header">bla</div>
<div id="awesomeness">awesomeness!</div>
<div id="footer">fdsfd</div>
</body>
</html>
...And I only want the tab to load #awesomeness from the page. How would I go about doing this? I've read into some guides that do that by adding a data-target="#youridhere" attribute to the HTML, but I'm still confused on how to implement the javascript. It seems like this is a convenient solution, as I won't be targeting the same ID in every page. Any clues on how to get the javascript working?
Thanks in advance!
The function that allow to load partial code of the response is the $.load() function.
Unfortunately, the tabs() feature does not use this function but use $.ajax instead.
You can try this solution:
You can try to stop the default processing on the beforeLoad callback and manage your ajax call with the $.load() method.
(base on the 1.9 documentation, you may should adapt)
$('#tabs').tabs({
// Callback run when selecting a tab
beforeLoad: function(event, ui) {
// If the panel is already populated do nothing
if (ui.panel.children().size() > 0)
return false;
// Make your own ajax load (with fragment feature)
ui.panel.load(ui.tab.attr('href') + ' #yourFragment');
// stop the default process (default ajax call should not be launched)
return false;
});
NOTICE: I'm not sure about extracting the URL with ui.tab.attr('href'), check before what object is ui.tab, but it should be easy to retrieve the href parameter.
Good luck
Got the solution :) Using one of the answers as a reference point, the tabs can now load a single element specified in the data-target attribute. Here is the modified version:
$(function() {
$('#tabs').tabs(
{
beforeLoad: function(event, ui) {
if (ui.panel.children().size() > 0)
return false;
ui.panel.load($('a', ui.tab).attr('href') + $('a', ui.tab).attr('data-target'));
return false;
}
});
});

What page is being loaded by Jquery Mobile

I'm tasked to execute specific page javascript on pagechange in Jquery Mobile (Such as geolocate the user on one page or show a Google map on another page)
Its really not clear how to execute javascript after a pagechange but i'm almost there, i was able to use
$(document).bind('pageinit', function(event){
loadGmaps();
geolocate();
});
But the problem is that this code executes on each page change/page init and if i'm not on a page that has a #map tag, it just executes code for nothing. Worst? Jquery keeps pages loaded in memory but hides them. So if i change page, it can reload the map 16 times in a row for nothing.
I'm really confused as to how you are supposed to bind specific page javascript in a jquery mobile loaded page. I'm lurked all around the web and i'm sure i'm not the only one looking for that specific trick...
Thanks
EDIT
I changed my code to reflect Jasper's solution, and it works fine except for the geolocation:
$(document).on('pageinit', '#wp-post-id-70', function(event){
geolocate();
});
$(document).on('pageinit', '.wp-post-type-spa', function(event){
loadGmaps();
});
The maps load fine on each page i visit that is a spa, but when i load a spa page from a fresh load, if i click on the logo to go back to the home page, it loads the home page and then fires the "geolocate" function but nothing happens in terms of geolocation:
function geolocate()
{
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
function(position){
$('#near_spa').load('?latitude='+position.coords.latitude.toString()+'& longitude='+position.coords.longitude.toString()+' #near_spa > *');
}
);
}else{
alert('Votre navigateur ne supporte pas la géolocalisation ou refuse l\'accès aux données de localisation');
}
}
The code really goes up to the navigator.geolocation.getCurrentPosition, it gets called but then pffff, nothing. If i reload the home page manually with F5, i now get the geolocation request...
EDIT
Never mind that "map" loads fine on each page, it doesn't anymore, probably me and my brain being too tired...
Therefore, the
$(document).on('pageinit', '.wp-post-type-spa', function(event){
loadGmaps();
});
Doesn't load the maps anymore at all and yes, i verified, the pages do feature a wp-post-type-spa class...
If you have code that only runs once per pseudo-page, then use the pageinit event, which only runs once every time a pseudo-page is added to the DOM.
You can also target specific pseudo-pages in your bind call:
$(document).on('pageinit', '#some-map-page', function(event){
loadGmaps();
geolocate();
});
This will only run when the pageinit event fires on an element with the ID of some-map-page. You could for example add a class to each pseudo-page element where you want to run the map code:
<div data-role="page" id="some-map-page" class="map-page">...</div>
Which would work with the following event binding:
$(document).on('pageinit', '.map-page', function(event){
loadGmaps();
geolocate();
});
Notice that I'm using .on() as a delegated event handler, which is very useful when using jQuery Mobile as you can't ever be sure when a pseudo-page exists in the DOM.

Resources