Jquery Mobile - $(document).ready(function() {}); - jquery-mobile

I am new to jquery mobile.
I need help understanding the equivalent of document.ready() for jquery mobile.
I have 2 jsp pages as follow:
page1.jsp
<head>
<script type="text/javascript">
$(document).on('pagebeforeshow', '#page1', function(event){
alert("page 1");
});
</script>
</head>
<body>
<div data-role="page" id="page1">
<header data-role="header">
</header>
<article data-role="content">
page 1
</article>
<footer data-role="footer" data-position="fixed">
<nav data-role="navbar">
<ul>
<li>Page 2</li>
</ul>
</div>
</body>
page2.jsp
<head>
<script type="text/javascript">
$(document).on('pagebeforeshow', '#page2', function(event){
alert("page 2");
});
</script>
</head>
<body>
<div data-role="page" id="page2">
<header data-role="header">
</header>
<article data-role="content">
page 2
</article>
<footer data-role="footer" data-position="fixed">
<nav data-role="navbar">
<ul>
<li>Page 1</li>
</ul>
</div>
</body>
So when I initially load page 1, I will get an alert "page 1". But when I navigate to page 2, I do not get the alert "page 2"
But on page 2, I navigate back to page 1, I get an alert "page 1"
So why don't I get "page 2" alert when I load page 2 via navigation?
I am trying to learn jquery mobile so please an explanation and any code example would help to me understand it a lot.
I tried to read through jquery mobile documentation but not understanding it.
Thank you!

Your script isn't running because it technically isn't being loaded. jQuery Mobile follows links by intercepting their normal functionality (which is to navigate to a new page) and instead loads the page's content via an AJAX request. If successful, it then takes the [data-role=page] element and adds it to your existing page. The result is that the new page is loaded, but you never really leave the page that you started from.
Anything not within a [data-type=page] element is not loaded during this, including your scripts. You can fix this by by moving your <script> tag inside of page2's [data-role=page] element. If you do this, keep in mind that any code loaded this will will remain as other pages are loaded, and you might have things start interacting in ways you never intended.
Another option is to simply force jQuery Mobile to actually navigate to new pages when links are clicked. Check out their documentation for how to do that.

Related

JQM 1.4 beta persistent navbar not keeping active state class for links

I'm facing an issue with the latest beta release of jQuery Mobile. I'm trying to implement a fixed persistent footer navbar, the persistent part is working but whenever I click a link and navigate to another page the ui-btn-active class is lost and no link appears selected.
Here's a demo fiddle that reproduces the issue: http://jsfiddle.net/koala_dev/DgdMg/2/
And here's the complete markup:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.0-beta.1/jquery.mobile.structure-1.4.0-beta.1.min.css" />
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.jquery.com/mobile/1.4.0-beta.1/jquery.mobile-1.4.0-beta.1.min.js"></script>
<script>
$(function() {
$("[data-role='header'],[data-role='footer']").toolbar();
$.mobile.window.triggerHandler("throttledresize");
});
</script>
</head>
<body>
<div data-role="header" data-position="fixed" data-id="header">
<h1>My fixed header</h1>
</div>
<div data-role="page" id="page-1">
<div data-role="content">
<p>Page 1 content goes here.</p>
</div>
</div>
<!-- /page -->
<div data-role="page" id="page-2">
<div data-role="content">
<p>Page 2 content goes here.</p>
</div>
</div>
<!-- /page -->
<div data-role="footer" data-position="fixed" data-id="footer">
<div data-role="navbar">
<ul>
<li>Page 1
</li>
<li>Page 2
</li>
</ul>
</div>
</div>
</body>
</html>
I followed the instruction from the demos in the docs (which don't seem to be complete) and placed the footer outside the page container. I tried adding .ui-state-persist to the first link and to both links but it didn't produce any effect and since even the demos are not working correctly I'm not sure how to proceed.
I would appreciate any insight on how to keep the ui-btn-active class for the clicked link.
Well, I found this on jQM updated demo page. Adding .ui-btn-active for external fixed toolbars depends on data-role=page's data-title attribute.
<div data-role="page" id="page-1" data-title="Page 1">
Navbar buttons text, should match data-title in order to determine which button should be updated with .ui-btn-active, as well as updating data-role=header title.
Demo
$(document).on("pageinit", function () {
$("[data-role='navbar']").navbar();
$("[data-role='header'], [data-role='footer']").toolbar();
});
// Update the contents of the toolbars
$(document).on("pageshow", "[data-role='page']", function () {
// Each of the four pages in this demo has a data-title attribute
// which value is equal to the text of the nav button
// For example, on first page: <div data-role="page" data-title="Info">
var current = $(this).jqmData("title");
// Change the heading
$("[data-role='header'] h1").text(current);
// Remove active class from nav buttons
$("[data-role='navbar'] a.ui-btn-active").removeClass("ui-btn-active");
// Add active class to current nav button
$("[data-role='navbar'] a").each(function () {
if ($(this).text() === current) {
$(this).addClass("ui-btn-active");
}
});
});
Source: http://view.jquerymobile.com/1.4.0-rc.1/dist/demos/toolbar-fixed-persistent/
I had this same issue for links in the navbar. It was very frustrating. I fired up firebug and debugged jqm. I ended up patching the jquery mobile code like so:
In jquery.mobile-1.4.0.js
From:
$navbtns.removeClass( $.mobile.activeBtnClass );
activeBtn.addClass( $.mobile.activeBtnClass );
To:
if ( !($navbtns.filter( ".ui-state-persist" ) ) ) {
$navbtns.removeClass( $.mobile.activeBtnClass );
activeBtn.addClass( $.mobile.activeBtnClass );
}
I minified jqm here: http://jscompress.com/

Dynamic listview not loading until refresh

I'm using JS render to create dynamic pages in Jquery Mobile for my Phonegap app. The problem however is that the listview isn't loaded until the page is refreshed. Clearly that's not what I want and in another app I used the exact same technique and the listview is loaded immediately. Thing is that there's no difference between the two, so I have no idea why it isn't working in this one.
Here's my script for loading the pages:
<script src="jquery/jsrender.min.js"></script>
<script type="text/javascript">
$(document).on('pageinit', '#kunstwerken_exp1', function (event, ui) {
var $page = $(event.target);
$.ajax({
dataType:"json",
url:"json/exp1_index.js",
success:function(data, textStatus, jqHXR){
for( var x = 0; x < data.length; x++){
//create valid unique IDs for each page.
data[x].id = data[x].link.replace("?","").replace("=","").replace("#","");
}
console.log("success:");
console.log(data);
$("#templateDropPoint").html($("#template").render(data));
$("#templateDropPoint").listview("refresh");
$("body").append($("#pagetemplate").render(data));
},
error:function(jqXHR, textStatus, errorThrown ){
console.log(textStatus+ " "+ errorThrown);
}
});
});
</script>
This is the HTML:
<div data-role="page" id="kunstwerken_exp1" data-url="kunstwerken_exp1">
<div data-role="content">
<ul data-role="listview" id="templateDropPoint"></ul>
</div><!-- /content -->
</div>
<script id="template" type="text/x-jsrender">
<li>
<a href="#{{>id}}">
<img src={{>img}} />
<h5><b>{{>naam}}</b></h5>
<h6>{{>kunstwerk}}</h6>
</a>
</li>
</script>
<script type="text/x-jsrender" id="pagetemplate">
<div data-role="page" id="{{>id}}">
{{if pagina}}
<div data-role="content">
<h1>{{>naam}} ({{:pagina.nationaliteit}})</h1>
<h2>{{:pagina.kunstwerk}}</h2>
<em>{{:pagina.onderschrift}}</em>
<div class="ui-grid-a my-breakpoint">
<div class="ui-block-a">
<div class="koloma">
<div class="callbacks_container">
<ul class="rslides">
<li id="callbacks1_s0">
<img src="{{:pagina.afbeelding1}}" alt=""><p class="caption">{{:pagina.onderschrift1}}</p>
</li>
</ul>
</div>
{{if pagina.videooff}}
<ul class="tabs">
<li><img src="images/video.png"/></li><br>
</ul>
{{/if}}
</div>
</div>
<div class="ui-block-b">
<div class="kolomb">{{:pagina.tekst}}</div>
</div>
</div>
</div>
{{/if}}
</div>
</script>
To understand this situation you need to understand how jQuery Mobile works. It uses AJAX to load other pages.
First page is loaded normally. Its HEAD and BODY is loaded into the DOM, and they are there to await other content. When second page is loaded, only its BODY content is loaded into the DOM. To be more precise, even BODY is not fully loaded. Only first div with an attribute data-role="page" will be loaded, everything else is going to be discarded. Even if you have more pages inside a BODY only first one is going to be loaded. This rule only applies to subsequent pages, if you have more pages in an initial HTML all of them will be loaded.
That's why your listview is show successfully only after a page refresh.
Here's an official documentation: http://jquerymobile.com/demos/1.2.0/docs/pages/page-links.html
Unfortunately you are not going to find this described in their documentation. Ether they think this is a common knowledge or they forgot to describe this like my other topics. (jQuery Mobile documentation is big but lacking many things).
I have another ANSWER that discusses this problem. Solutions and working examples can be found there.

How to add header bar dynamically with elegant style in jQuery Mobile

My mobile website dynamically adds the header bar to reduce code redundancy.
However, I'm stuck with styling header section of a jquery mobile page.
When I see the generated HTML tags, it looks okay,
but its element is not decorated by jQuery Mobile.
After adding the content, I invoked
$(pageId).trigger('create');
Do you have any ideas?
This worked for me : http://jsfiddle.net/emBxx/2/
HTML:
<script type="text/javascript" src="js/main.js"></script>
...
<div data-role="page" data-theme="b">
<header></header>
<div data-role="content">
<div class="content-primary">
<br />
<ul data-role="listview" data-filter="true">
<li>Some</li>
<li>random</li>
<li>searchable</li>
<li>content</li>
<li>(list!)</li>
</ul>
</div><!--/content-primary -->
</div>
<footer></footer>
</div><!-- page end-->
<script>
appendJQMHeader('Injected header !');
appendJQMFooter('—Injected ftr!', 'JQM 1.3.1Beta');
</script>
JS, in js/main.js:
function appendJQMHeader(pageTitle) {
$('header').replaceWith(
'<header data-role="header" data-theme="f">'+
'<h1>'+pageTitle+'</h1>'+
'Home'+
'</header><!-- /header -->');
}
function appendJQMFooter(left, right) {
$('footer').replaceWith('<footer data-role="footer" data-theme="f" class="jqm-footer"><p>©'+left+'!</p><p class="jqm-version">—'+right+'</p></footer>');
}
Note: for JSfiddle, it require 'Framework & extension > No wrap - in <head>'
For stand alone version, it worked fine with html head calling js/main.js containing the JS. Then html body with appendJQMHeader() & appendJQMFooter(). See the fiddle :)
Instead of invoking the trigger method, I executed the below command, and it works well.
$('#pageHome').closest(":jqmData(role='page')").trigger('pagecreate');

Getting a function to run everytime a jquery mobile page is loaded

I'm trying to get a function to run everytime jquery mobile loads a new page into the application, but currently, the code only gets run once on the first instance of a page loading.
HTML:
<div id="pageID" data-role="page" class="content_page">
<div data-role="header" data-id="bestHeader" data-position="fixed">
<h1>Header</h1>
</div><!-- end header -->
<section data-role="content">
<h2>Header2</h2>
<p>Content goes here</p>
</section>
<div class="bottomAd" data-role="footer" data-position="fixed">
<img src="ad2.jpg" width="100%">
</div>
<div data-role="footer" data-id="bestFooter" data-position="fixed">
<nav data-role="navbar">
<!-- navBar here -->
</nav>
</div><!-- end footer -->
</div><!-- end page -->
<div id="pageID2" data-role="page" class="content_page">
<div data-role="header" data-id="bestHeader" data-position="fixed">
<h1>Header</h1>
</div><!-- end header -->
<section data-role="content">
<h2>Header2</h2>
<p>Content goes here</p>
</section>
<div class="bottomAd" data-role="footer" data-position="fixed">
<img src="ad2.jpg" width="100%">
</div>
<div data-role="footer" data-id="bestFooter" data-position="fixed">
<nav data-role="navbar">
<!-- navBar here -->
</nav>
</div><!-- end footer -->
</div><!-- end page -->
Javascript
$(".content_page").live('pageinit', function(event) {
if ($(".bottomAd img[src*=ad]").length >= 1) {
console.log($(".bottomAd img[src*=ad]").length);
$(".bottomAd").remove();
}
No matter how many times you click back and forth between the two pages, the console.log only gets called once, and the .bottomAd class gets removed document wide on the first instance of the page getting clicked on. I'd like to have the function run everytime the page is called, so each time the "page" is checked for having an image with a src that contains "ad" in the bottomAd div on that specific page, and then removed if so.
If you want to do work on something each time a page is shown (either the first time or subsequent visits) then I suggest using pageshow, pageinit only fires the first time a page is shown and jQuery Mobile will keep pages in the DOM sometimes. If you want to run some code only the first time a user goes to a page then use pageinit but bind your delegated event handler to the document element.
I would also make your selector more specific (to the current page) so you don't work on elements on pages not being viewed like so:
...
//`this` refers to the `<data-role="page">` pseudo-page element being bound to
$(this).find(".bottomAd").remove();
..
Your delegated event handler should bind to an element always in the DOM, for example document:
$(".content_page").live('pageinit', function(event) {
should be
$(document).on('pageinit', '.content_page', function () {...});
Note that .live() was depreciated in jQuery 1.7 and that .on() is the new flavor.
You probably want to use the pageshow event, you also might want to use .on instead of .live as .live is depreciated,
For example
$(document).on('pageshow','.content_page' function(event) {
if ($(".bottomAd img[src*=ad]").length >= 1) {
console.log($(".bottomAd img[src*=ad]").length);
$(".bottomAd").remove();
}
There is also a pageload event but that is fired when an external page is attached to the DOM.
pageload Event
"Triggered after the page is successfully loaded and inserted into the DOM. Callbacks bound to this event will be passed a data object as its 2nd arg. "
http://jquerymobile.com/test/docs/api/events.html

How to get alert to only appear once in jQuery Mobile multiple page html

I have a multipage html (using "div data-role="page") that displays 4 pages of a document that can be swiped left or right to move between the pages back and forth.
I have an alert that I want to pop-up only when the page first loads (telling the user they can swipe to move back and forth between pages).
My problem is that it keeps popping up again every time a swipe to a new page is made and I only want it to alert them once when the page loads.
I've tried moving the script from the head to inside the element, and I've tried binding it to all the different pagecreate, pagebeforecreate, pageinit, etc. events and can't seem to figure it out.
I appreciate any advice or direction.
Here's the alert code that is currently showing on every page when swiped:
<script type="text/javascript">
$('div').live("pagecreate",function(event){
alert('Swipe left and right to move between the 5 pages of this lead sheet');
});
</script>
You can bind to the id for the page DIV (ex: div#home).
<script type="text/javascript">
$('div#home').live("pagecreate", function (event) {
alert('Swipe left and right to move between the 5 pages of this lead sheet');
});
</script>
...
<div data-role="page" id="home">
Live Example:
http://jsfiddle.net/FcjNR/1/
JS
var $alerted = false;
$('div').live('pageshow',function(event, ui) {
// Check for secure token here
if($alerted == false) {
$alerted = true;
alert('Can you see me now?');
}
});
HTML
<div data-role="page" id="home">
<div data-role="content">
<ul data-role="listview" data-inset="true" data-theme="c" data-dividertheme="f">
<li data-role="list-divider">Alert once</li>
<li>Alert Page</li>
</ul>
</div>
</div>
<div data-role="page" id="alert">
<div data-role="content">
<ul data-role="listview" data-inset="true" data-theme="c" data-dividertheme="f">
<li data-role="list-divider">The Alert</li>
<li>Home</li>
</ul>
</div>
</div>

Resources