Phonegap + Jquery Mobile: initialization / registration best practices - jquery-mobile

I am developing an Phonegap (3.3.0) + Jquery Mobile (1.4) app.
I get an infinite loading page (white page with ui-loader icon). This is erratic and sometimes the app starts well.
I see a very strange bug: none of the first "console.logs" I use in my js file are displayed in the Phonegap Build Weinre debug console.
Only after a certain line (which contain by the way the first asynchronous function) the console.log are displayed in the Weinre console.
So I guess I have a binding order problem related to Jquery Mobile and Phonegap, but I can't find what's wrong in my initialization.
Can I be also due to the order in which I call js files in my index.html ?
I followed this post to register Phonegap and JQM : Correct way of using JQuery-Mobile/Phonegap together?
recommended here : jQuery Mobile : What is the order of page events triggering?
by #Gajotres.
Can you help ?
Thanks
HTML:
<!DOCTYPE html>
<html>
<head>
...
</head>
<body>
<!-- SPLASH PAGE -->
<div id="splash-page" data-role="page">
<div class='toastenjs' style='display:none'></div>
<center id="splashLogoCenter">
<img src="images/splash.png" width="200" />
</center>
</div>
<!-- WELCOME PAGE -->
<div id="welcome-page" data-role="page">
...
</div>
<script src="js/jquery-1.9.1.js"></script>
<script src="js/jquery.jsonp-2.4.0.min.js"></script>
<script src="js/functions.js"></script>
<script src="js/functionCUgly.js"></script>
<script src="js/boardDims.js"></script>
<script src="phonegap.js"></script>
<script src="js/jquery.mobile.config.js"></script>
<script src="js/jquery.mobile-1.4.3.min.js"></script>
<!--POUCHDB -->
<script src="js/pouchdb-2.2.3.min.js"></script>
<!-- Flexslider-->
<!-- <script src="js/flexslider-v2.js"></script>--> <!-- v2.2 doesn't work, maybe because we're not using last versions of jquery and jqm -->
<script src="js/flexsliderV2.3.js"></script>
<!-- iScroll-->
<script type="application/javascript" src="js/iscroll.js"></script>
<script type="application/javascript" src="js/jquery.mobile.iscrollview.js"></script>
<!-- Add2home : create a shortcut icon of the wep app on the phone homescreen -->
<script type="application/javascript" src="js/add2home.js"></script>
<script src="js/GoogleLogin.js"></script> <!--Phonegap module by eric valenzia https://github.com/valenzia10/PhonegapGoogleLogin-->
<script src="js/jquery.ddslick.min.js"></script>
<script src="js/jquery-geturlvar.js"></script>
<script src="js/html2canvas.js"></script>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
if (typeof(google) != 'undefined'){
google.load('visualization', '1.0', {'packages':['corechart']});
}
</script>
JS file:
var deviceReadyDeferred = $.Deferred();
var jqmReadyDeferred = $.Deferred();
$(document).one("mobileinit", function () {
console.log('mobileinit just fired'); //this one is not displayed in the weinre console
jqmReadyDeferred.resolve();
});
if ( isPhoneGap() ) {
document.addEventListener("deviceReady", onDeviceReady, false);
function onDeviceReady() {
deviceReadyDeferred.resolve();
}
$.when(deviceReadyDeferred, jqmReadyDeferred).then( EVERYTHING() ); // !!!!! normalement il faut virer ces parenthèses pour respecter le $.when....mais ça fait tout bugger !!!!!!!!!
} else {
console.log("NOT Running on PhoneGap!");
$.when(jqmReadyDeferred).then( EVERYTHING );
}
function EVERYTHING() {
console.log("on est entré dans EVERYTHING()"); //not displayed in the weinre console
insideEVERYTHING = 1;
console.log("jqmReadyDeferred is "+jqmReadyDeferred.state()); //not displayed in the weinre console
console.log("deviceReadyDeferred is "+deviceReadyDeferred.state()); //not displayed in the weinre console
//FOR EVERY PAGE
$(document).on('pagecontainershow', function (e, ui) {
//...
});
$(document).on('pagecontainershow', function (e, ui) {
//...
});
// --------------- SPLASH PAGE ---------------------
//$(document).on('pagecreate','#splash-page', function(){
$(document).on('pagecontainershow', function (e, ui) {
var activePageId = $(':mobile-pagecontainer').pagecontainer('getActivePage').attr('id');
if (activePageId === 'splash-page') {
console.log("we are in splash-page");
if (typeof debugOptionUseLocalDB != 'undefined' && debugOptionUseLocalDB) {
fallbackToLocalDBfile();
console.log('on yess');
}else{
if(connectionStatus == 'online'){
console.log("launching getJsonpFile...");
//DEBUG TIMER
var time=[];
var dummy;
dummy = new Date().getTime();
time.push(dummy);
getJsonpFile(dbUrl())
.done(function(data) {
console.log("...getJsonpFile done.");
if(localStorage) {
if ( isPhoneGap() || !isIOS() ) { //BUG iOS safari doesn't work with this (Cf. Philippe's ipad), si on est sur phonegap ok, si on n'est pas sur phonegap et pas sur iOS ok
localStorage.setItem("proDB", JSON.stringify(data)); //write to localStorage
}
}
//...JQM bindings are continued below

The best registration is the following :
var isPhoneGap;
var deviceReadyDeferred = $.Deferred();
var jqmReadyDeferred = $.Deferred();
isPhoneGap = checkIfPhoneGap();
if ( isPhoneGap ) {
$.when(deviceReadyDeferred, jqmReadyDeferred).done( Everything );
} else {
console.log("NOT Running on PhoneGap!");
$.when(jqmReadyDeferred).done( Everything );
}
$(document).on("mobileinit", function () {
//alert('mobileinit just fired');
//popShortToast("mobileinit just fired");
jqmReadyDeferred.resolve();
});
document.addEventListener("deviceReady", onDeviceReady, false);
function onDeviceReady() {
//popShortToast("deviceReady just fired");
deviceReadyDeferred.resolve();
}
function checkIfPhoneGap() {
var app = document.URL.indexOf( 'http://' ) === -1 && document.URL.indexOf( 'https://' ) === -1; // && document.URL.indexOf( 'file://' );
if ( app ) {
return true;
} else {
return false;
}
}
function Everything() {
//enter your JQM bindings here, and use Phonegap's features
}

Related

video.js not working properly with jquery mobile

I am trying to use video.js(gitHub link - https://github.com/videojs/video.js ) plugin in my jquery mobile project to get custom video player, I followed all the documentation from this site (http://videojs.com/), but due to some reasons I am getting following errors -
The element or ID supplied is not valid. (videojs).
this[a] is not a function.
My code -
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="Js/jquery.js"></script>
<script src="Js/jquery.signalR-2.1.2.min.js"></script>
<script src="Js/jquery.mobile-1.4.5.js"></script>
<link href="mcss/jquery.mobile-1.4.5.css" rel="stylesheet" />
<link href="http://vjs.zencdn.net/4.12/video-js.css" rel="stylesheet">
<script src="http://vjs.zencdn.net/4.12/video.js"></script>
<script type="text/javascript">
videojs("Mobile_VIDEO_1").ready(function () {
var vid = this;
vid.on("ended", function () {
alert("is");
$("#videoListXYZ").css("display", "block");
});
});
</script>
</head>
<body>
<div data-role="page" id="p-forget-password">
<div data-role="main" class="ui-content ui-body-cf ui-responsive">
<!-- inserted dyanamically using handlebars template "http://handlebarsjs.com"/ -->
<video id="Mobile_VIDEO_1" class="video-js vjs-default-skin" controls data-id="{{VideoId}}" data-setup='{ "plugins" : { "resolutionSelector" : { "default_res" : "360" } } }' autoplay="autoplay" width="340" height="250">
<source src="{{Path}}" type="video/mp4" data-res="360" />
</video>
</div>
</div>
</body>
Please help me to find out what I am doing wrong.
-I tried using putting videojs(xyx).ready(....) inside document.ready
- I also tried sending my script at the bottom of my page as suggested by (http://help.videojs.com/discussions/problems/985-api-ready-call-fails), but it still not working
After many hit and trial, I realized that my event is firing much before the DOM initialization, so I searched for how to check when the whole page is fully loaded and I come across this document (https://css-tricks.com/snippets/jquery/run-javascript-only-after-entire-page-has-loaded/) from this link I used this
$(window).bind("load", function() {
// code here
});
to check if my page is fully loaded or not . my final solution is mentioned below , if any of you come across a better solution then please share that to help others.
$(window).bind("load", function () {
var videoPath = $('#sv1').attr('src'); //to get the path of video
if (videoPath != "" && videoPath != null) { //checking for non-empty path
console.log(videoPath);
videojs('MY_VIDEO_1', { "plugins": { "resolutionSelector": { "default_res": "360" } } }, function () {
console.log('Good to go!');
this.play();
this.on('ended', function () {
console.log('awww...over so soon?');
$("#videoList").css("display", "block");
});
});
$("#replay").click(function () {
var myPlayer = videojs("MY_VIDEO_1");
myPlayer.play();
});
}
});

Jquery Mobile pageshow event firing twice

I currently have a mobile site I am building and I am having trouble with integrating a custom JQuery widget. For some reason the the pageshow event is firing twice for whichever page is loaded first.
For ease of understanding I have created two HTML pages
Page 1
<!doctype html>
<head>
<meta charset="utf-8">
<title>One</title>
<link rel="stylesheet" href="https://code.jquery.com/mobile/1.4.0/jquery.mobile-1.4.0.min.css" />
<script type="text/javascript" src="https://code.jquery.com/jquery-1.10.2.min.js"></script>
<script type="text/javascript">
$(document).on("mobileinit", function () {
$.mobile.changePage.defaults.reloadPage = true;
});
</script>
<script type="text/javascript" src="https://code.jquery.com/mobile/1.4.0/jquery.mobile-1.4.0.js"></script>
</head>
<body id="default">
<div data-role="page" id="content-one">
<div role="main" class="ui-content" id="one-content">
One<br/>
back to two
</div>
<script type="text/javascript">
(function($, undefined) {
$.widget("test.stuff", {
_create : function() {
console.log("create");
},
_init : function() {
console.log("_init");
},
destroy: function () {
this.element.empty();
$.Widget.prototype.destroy.call(this);
}
});
})(jQuery);
</script>
<script type="text/javascript">
$(document).on("pageshow", "#content-one", function () {
console.log("pageshow1");
$("#content-one").stuff({});
});
$(document).on("pagebeforeshow", "#content-one", function () {
console.log("pagebeforeshow1");
});
</script>
</div>
</body>
</html>
Page 2
<!doctype html>
<head>
<meta charset="utf-8">
<title>Two</title>
<script type="text/javascript" src="https://code.jquery.com/jquery-1.10.2.min.js"> </script>
<script type="text/javascript">
$(document).on("mobileinit", function () {
$.mobile.changePage.defaults.reloadPage = true;
});
</script>
<script type="text/javascript" src="https://code.jquery.com/mobile/1.4.0/jquery.mobile-1.4.0.js"></script>
</head>
<body id="default">
<div data-role="page" id="content-two">
<div role="main" class="ui-content">
Two<br/>
back to one
</div>
<script type="text/javascript">
$(document).on("pageshow", "#content-two", function () {
console.log("pageshow2");
});
$(document).on("pagebeforeshow", "#content-two", function () {
console.log("pagebeforeshow2");
});
</script>
</div>
</body>
</html>
To recreate load page one first, navigate to page two using link, then navigate to page one using link.
When page one is loaded again the pageshow event is fired twice. I have the reloadPage set to true as I have dynamic content for my pages and I cannot serve cached pages.
I very well could be using the events incorrectly.
Try substituting your $(document).on("pageshow",...) with $(document).one("pageshow", ...), which restricts the event to one call http://api.jquery.com/one/.
The problem is that using on in the inline script creates a new event each time the page is loaded. So the first time you load the page, the inline script is executed and the pageshow event is triggered. The second time a new event is triggered again, but the first one is still listening to content-one pageshow. In fact, if you repeat the process you'll see the log three, four, ... times.
Another option could be to create a script in the head section which sets up all required triggers in $(document).on("pageshow", "#content-one", ...), $(document).on("pageshow", "#content-two", ...). In this case, the script will only be initialized once, so it will work.
Wasted about 2 hours trying to do all the fixes on here and other sites. I gave up and put an if statement in their to prevent it from firing again
var hasDownload = false;
$(document).on("pageinit", "#mypage",function(event){
if (hasDownload === false) {
hasDownload = true;
// do some work
}
);
Try to remove the page on hide event, like so :
$(document).on("mobileinit", function () {
$.mobile.changePage.defaults.reloadPage = true;
$(docuement).on('pagehide', function (event, ui) {
$(event.target).remove();
});
});
Remenber that if you don't disable ajax, all request will be with AJAX

Phonegap Cordova does not fire JQM pageinit

I have made lots of research on this topic but I did not find an appropriate answer.
My problem is that when I use Cordova/Phonegap with JQM, the $(document).ready is fired but not the $(document).on('pageinit') which is recommanded to use with JQM.
<script type="text/javascript" src="cordova-2.7.0.js"></script>
<script src="js/jquery-1.10.1.min.js" type="text/javascript"></script>
<script>
var deviceReadyDeferred = $.Deferred();
var jqmReadyDeferred = $.Deferred();
document.addEventListener("deviceReady", deviceReady, false);
function deviceReady() {
deviceReadyDeferred.resolve();
}
$(document).on("mobileinit", function () {
jqmReadyDeferred.resolve();
});
$.when(deviceReadyDeferred, jqmReadyDeferred).then(doWhenBothFrameworksLoaded);
function doWhenBothFrameworksLoaded() {
console.log('device ready');
$(document).on("pageinit",function(){
console.log("document pageinit fired");
}
}
</script>
<script src="js/jquery.mobile-1.3.1.min.js" type="text/javascript"></script>
<script src="js/buttonset.js" type="text/javascript"></script>
This page is hosted on a remote server. In this case, device ready appears in the console but not document pageinit fired. If I replace $(document).on("pageinit",function(){ by $(document).ready(function(){, both logs appear but I dislike this solution.
Could you please tell me where I got wrong ?
Thanks beforehand.
try this sequence of code in script tag.
/* Initialization of PhoneGap and jQM */
var deviceReadyDeferred = $.Deferred();
var jqmReadyDeferred = $.Deferred();
//initialize PhoneGap
document.addEventListener("deviceReady", deviceReady, false);
function deviceReady() {
}
//initialize jQM
$(document).on("mobileinit", function () {
//hack to fix android page transition flicking issue
if (navigator.userAgent.indexOf("Android") != -1){
$.extend( $.mobile , {
defaultPageTransition: 'none'
});
}
setCustomThemeAndOptions();
jqmReadyDeferred.resolve();
});
//When both PhoneGap and jQM are ready, initialize language setting
$.when(deviceReadyDeferred, jqmReadyDeferred).then(function(){
deviceDeferred = true;
});

Jquery mobile is not applying styles when the page is dynamically added

Hi I have a small app that uses JQM and Sammy. I am using Sammy to load pages dynamically and appending to the body of my index.html. the problem is i dont see the JQM themes are getting applied and there are no errors in console as well.
Are there any reason for this. I do call the following
context.render('view/abc.template')
.appendTo(context.$element(),function(){
$(document).ready(function () {
$("#container").trigger('pagecreate');
});
});
Thanks
This is how I did it;
1) firstly I disabled my JQM routing like so in a file called plugins.js;
$(document).bind("mobileinit", function() {
/**
* check out http://coenraets.org/blog/2012/03/using-backbone-js-with-jquery-mobile/ for more details
*/
$.mobile.ajaxEnabled = false;
$.mobile.linkBindingEnabled = false;
$.mobile.hashListeningEnabled = false;
$.mobile.pushStateEnabled = false;
});
This code was loaded before I loaded JQM, like so;
<script src="//code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="js/plugins.js"></script>
<script src="//code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.js"></script>
<script src="js/vendor/sammy/sammy.js" type="text/javascript" charset="utf-8"></script>
<script src="js/vendor/sammy/plugins/sammy.template.js" type="text/javascript" charset="utf-8"></script>
<script src="js/main.js"></script>
Then my main.js function looks like this;
(function($) {
var app = $.sammy('#main', function() {
this.use('Template');
this.get('#/', function(context) {
context.load('/templates/index.template', function() {
$("#container").trigger('pagecreate');
}).appendTo(context.$element());
});
this.get('#/landing', function(context) {
context.load('/templates/landing.template', function() {
$("#container").trigger('pagecreate');
}).replace(context.$element());
});
});
$(function() {
app.run('#/');
});
})(jQuery);
I think you are not far off on your code snippet above. NB you have your $(document).ready function as a callback to appendTo, which does not take a callback. You will see mine is in load() which does

Reload Ajax Tab with jquery UI 1.9+

While their are plenty of posts regarding reloading a jQueryUI tab via the load method, I can't seem to make it work in 1.9+. I wish I could see a way to show this in a fiddle, but as I don't... note that the refresh button/function works every time in the following nested tabs set-up under 1.8+ but works only once under 1.9+, and fails after that. In context, (loading dynamic content via php under wordpress) it doesn't work at all. According to the ajaxStart()ajaxStop() function calls, an ajax call is made every time the refresh button is clicked, however the content (watch the date/time under tab E or tab A/sub parent E) is only reloaded on the first click of the #refresh button, which fails to re-load the tab content on subsequent clicks.
stye.css
div.clear { clear:both; }
#refresh { position: relative; top:-40px; left:300px; }
#loading
{ display:none;
position: absolute;
top:100px;
left:300px;
font-size: 200%;
z-index:1001;
border:3px solid green;
background:#ffffff;
}
tabs.js
jQuery(function()
{ set_tabs();
jQuery('body').on("click", "#refresh", function()
{ jQuery('.tabset ul li a').each(function()
{ var link = jQuery(this);
var tab = link.parent();
var tabset = link.closest('div.tabset');
if(tabset.is(':visible') && tab.hasClass('ui-state-active')) index = link.text().replace(/ /g, '_');
});
jQuery(".tabset").tabs( "load" , index );
});
jQuery("#loading").ajaxStart(function() {jQuery(this).show();});
jQuery("#loading").ajaxStop(function(){ jQuery(this).fadeOut(1500); });
});
function set_tabs()
{ jQuery('.tabset').tabs({ cache:true }); }
index.html
<!--script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js"></script>
<link type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.17/themes/smoothness/jquery-ui.css" rel="stylesheet"-->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/jquery-ui.min.js"></script>
<link type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/themes/smoothness/jquery-ui.css" rel="stylesheet">
<script type="text/javascript" src="tabs.js"></script>
<link type="text/css" href="style.css" rel="stylesheet" />
<div id="parentTabSet" class="tabset">
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
<li>E</li>
</ul>
<input type='button' id='refresh' value='refresh' />
<div id='loading'>Loading...</div>
<div id="A" class="tabset">
<ul>
<li>A_1</li>
<li>A_2</li>
<li>parent E</li>
</ul>
<div id="A_1"><p>A_1 - FOO</p></div>
<div id="A_2"><p>A_2 - BAR</p></div>
</div>
<div id="B"><p>Div B</p></div>
<div id="C"><p>Div C</p></div>
<div id="D"><p>Div D</p></div>
</div>
tabs_e.html
<script>
jQuery( function()
{ set_tabs();
var d = new Date();
jQuery('#E_1 p').text(d);
jQuery('#E_2 p').text(d);
});
</script>
<div class="tabset">
<ul>
<li>E_1</li>
<li>E_2</li>
</ul>
<div id="E_1"><p>E_1 - BAR</p></div>
<div id="E_2" class='clear'><p>E_2 - BAZ</p></div>
</div>
The .live() function has been deprecated for a while now, and support is completely gone in jQuery 1.9+. Use this:
$(document).on("click", "#refresh", function() {
// your current "live" code
});
So it turns out that not only has the cache option been deprecated in 1.9+ it's legacy behavior has been altered such that (if used) the load method will not reload the tab content.
The approach I've come up with is -- I think -- an abomination which I'm hoping some one might provide a cleaner alternative to. (oh pleeeaazzz!) Anyway, FWIW... here's what I came up with.
tabs.js (revisited)
jQuery(function()
{ set_tabs();
jQuery(document).on("click", "#refresh", function()
{ refresh = {};
refresh.tab = true;
jQuery('.tabset ul li a').each(function()
{ var link = jQuery(this);
var tab = link.parent();
var tabset = link.closest('div.tabset');
if(tabset.is(':visible') && tab.hasClass('ui-state-active')) index = link.text().replace(/ /g, '_');
});
jQuery(".tabset").tabs( "load" , index );
});
jQuery("#loading").ajaxStart(function() {jQuery(this).show();});
jQuery("#loading").ajaxStop(function(){ jQuery(this).fadeOut(1500); });
});
function set_tabs()
{ jQuery('.tabset').tabs(
{ beforeLoad: function( event, ui)
{ if(typeof refresh.tab =='undefined')
{ if ( ui.tab.data( "loaded" ))
{ event.preventDefault();
return;
}
ui.jqXHR.success(function() { ui.tab.data( "loaded", true );});
} else refresh={};
}
});
}

Resources