I want to show loading animation spinner in a JQueryMobile page which is loaded w/ ajax off.
The page is loaded with data-ajax="false" or rel="external"
I tried on pagebeforecreate and pageshow event but its NOT working as I expected:
$( '#page' ).live( 'pagebeforecreate',function(event){
$.mobile.loading('show');
});
$( '#page' ).live( 'pageshow',function(event){
$.mobile.loading('hide');
});
There's a slight problem with your request.
First, you will not be able to show/hide ajax loader without set interval. There's is only one situation where this is possible without and that is during the pageshow event. In any other case setinterval is needed to kickstart to loader.
Here's a working example: http://jsfiddle.net/Gajotres/Zr7Gf/
$(document).on('pagebeforecreate', '#index', function(){
var interval = setInterval(function(){
$.mobile.loading('show');
clearInterval(interval);
},1);
});
$(document).on('pageshow', '#index', function(){
var interval = setInterval(function(){
$.mobile.loading('hide');
clearInterval(interval);
},1);
});
But here we have a different problem, unless your page is complex enough new page will be loaded very fast. jQuery mobile has internal timer that looks how fast page is loading into the DOM. If page is complex and loading takes more then 10 ms it will display the loader in any other case loader will not be shown, no matter how hard you try.
Also take notice that only DOM loading will count into that 10 ms. Page styling is out of calculation. So no matter if page loading looks longer only DOM loading counts.
My example will not show loader because it is a very simple example. But you can see it is working example if you comment this line:
$.mobile.loading('hide');
Related
I am trying to show the loading animation during a function call that takes some time. The function call is searching a large array that is already loaded. After the search, matching items are inserted into a table. The table is cleared prior to starting the search.
The problem is the animation only displays during the brief moment when the page updates.
Here is my code:
var interval = setInterval(function ()
{
$.mobile.loading('show');
clearInterval(interval);
}, 1);
DoSearch(term, function ()
{
var interval = setInterval(function ()
{
$.mobile.loading('hide');
clearInterval(interval);
}, 1000);
});
//The search function looks like this (detail omitted for brevity):
function DoSearch(term)
{
$("table#tableICD tbody").html('');
// also tried:
/*$("table#tableICD tbody")
.html('')
.table()
.closest("table#tableICD")
.table("refresh")
.trigger("create");*/
var tr = '';
$.each(codes, function (key, value)
{
// determine which items match and add them as table rows to 'tr'
});
$("table#tableICD tbody")
.append(tr)
.closest("table#tableICD")
.table("refresh")
.trigger("create");
callback();
}
The search works properly and adds the rows to the table. I have two unexpected behaviors:
The table does not clear until the search is complete. I have tried adding .table("refresh").trigger("create") to the line where I set the tbody html to an empty string. This does not help. (see commented line in the code)
As I mentioned, the animation displays briefly while the screen is refreshing. (Notice I set the interval to 1000 in the second setInterval function just so I could even see it.)
The suggestions I have read so far are to use setInterval instead of straight calling $.mobile.loading, which I have done and placing the search in a function and using a callback, which I have also done.
Any ideas?
Let me give you a few suggestions; they will probably not solve all your issues but they may help you found a solution.
jQuery Mobile is buggy, and for some features, we will never know were they intended to work like that or are they just plain bugs
You can call $.mobile.loading('show') on its own only in pageshow jQuery Mobile event. In any other case, you need to do it in interval or timeout.
It is better to do it in timeout, mostly because you are using less code. Here an example I made several years ago: http://jsfiddle.net/Gajotres/Zr7Gf/
$(document).on('pagebeforecreate', '[data-role="page"]', function(){
setTimeout(function(){
$.mobile.loading('show');
},1);
});
$(document).on('pageshow', '[data-role="page"]', function(){
// You do not need timeout for pageshow. I'm using it so you can see loader is actualy working
setTimeout(function(){
$.mobile.loading('hide');
},300);
});
It's difficult to enhance any jQuery Markup in real time after a page was loaded. So my advice is to first generate new table content, then clean it, and then update markup using .table("refresh").
Do table refresh only once, never do it several times in the row. It is very resourced heavy method and it will last a very long time if you run it for every row
If you are searching on keypress in the input box then showing it in the table; that is the least efficient method in jQuery Mobile. jQM is that slow, it is much better to use listview component which is least resource extensive.
I'm using jquery mobile v1.3.2
For some reasons I want to set an global pagechange event to prepare all of my pages :
var Front = {
initDom : function($dom) {
// here i can bind some events in my page
$(".someButton",$dom).bind("tap",function(){
alert("some actions");
});
// etc.....
});
}
$(document).on("pagechange", function(event, data) {
Front.initDom($(data.toPage));
});
This works well. But it is triggered at each page change. And some times it will init the same event twice and that will lead to some bugs.
Now i have tested to do it with the event pageinit or pagecreate but both are triggered before the page is ready and $("ui-page-active"); is empty.
I have though about some setTimeout, but that's definitively a bad idea.
I have also though to init everything at the first pageinit and unbind it. But ajax called page wont be bound.
It there some good workarround ?
You can use pageinit and then get the id of the page from the event target object:
$(document).on("pageinit", function(e){
alert(e.target.id);
});
DEMO
Adding my bindings to the pageinit event like so:
$('#mypage').on("pageinit", function () {
$('#login-sumbit').on('click', function () {
console.log('button clicked');
});
});
I would expect pageinit to bind the click event once only. But what happens in my single page app is that the button is binding every time the page is loaded even when clicking back.
This results in undesirable multiple duplicate binds. Any ideas on what event to use to bind only once in my single page app, so that loading the page again (back button, loading inline page) in the same session doesn't re-bind?
Looks like I found the answer myself, turns out quite rightly pageinit fires every time the page is loaded even though it's not reloading from the server, otherwise what would fire when a new page is shown.
pageinit is the right event but I need to use .one not .on, .one will bind one time only.
$('#mypage').on("pageinit", function () {
$('#login-sumbit').one('click', function () {
console.log('button clicked');
});
});
Now everything works as expected. Better still I've found you can use .one with the pageinit event for even more control over your bindings and data loads perfect for my requirements.
http://api.jquery.com/one/
You could use:
$('#login-sumbit').off('click').on('click', function(e) {
console.log('button clicked');
});
I fill list dynamically, and after that on click I have multiple calls of event. 1st time it is repeated 1 time, 2nd time 2 times, 3rd time 3 times, etc...
First, more about this problem can be found in my other answer: jQuery Mobile: document ready vs page events
Prevent multiple event binding/triggering
Because of interesting jQM loading architecture, multiple event triggering is a constant problem. For example, take a look at this code snipet:
$(document).on('pagebeforeshow','#index' ,function(e,data){
$(document).on('click', '#test-button',function(e) {
alert('Button click');
});
});
Working jsFiddle example: http://jsfiddle.net/Gajotres/CCfL4/
Each time you visit page #index click event will is going to be bound to button #test-button. There are few ways to prevent this problem:
Solution 1:
Remove event before you bind it:
$('#index').live('pagebeforeshow',function(e,data){
$('#test-button').die().live('click', function(e) {
alert('Button click');
});
});
Working jsFiddle example: http://jsfiddle.net/Gajotres/K8YmG/
In case you have different events bound to an object:
$('#index').live('pagebeforeshow',function(e,data){
$('#test-button').die('click').live('click', function(e) {
alert('Button click');
});
});
Solution 2:
Use a jQuery Filter selector, like this:
$('#carousel div:Event(!click)').each(function(){
//If click is not bind to #carousel div do something
});
Because event filter is not a part of official jQuery framework it can be found here: http://www.codenothing.com/archives/2009/event-filter/
In a nutshell, if speed is your main concern then Solution 2 is much better then Solution 1.
Solution 3:
A new one, probably an easiest of them all.
$(document).on('pagebeforeshow', '#index', function(){
$(document).on('click', '#test-button',function(e) {
if(e.handled !== true) // This will prevent event triggering more then once
{
alert('Clicked');
e.handled = true;
}
});
});
Working jsFiddle example: http://jsfiddle.net/Gajotres/Yerv9/
Tnx to the sholsinger for this solution: http://sholsinger.com/archive/2011/08/prevent-jquery-live-handlers-from-firing-multiple-times/
More info
If you want to find more about this problem take a look at this article, working examples are included.
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.