Collapisble Set, jQuery Mobile, inject AJAX content - jquery-mobile

Given a basic jQuery Mobile Collapisible Set, how can I get AJAX content before the toggle event fires? I am using jQM to create the following:
<div id="test" data-role="collapsible-set" data-inset="false">
<div data-role="collapsible" data-collapsed="true" data-mini="true">
<h2>Title #1</h2>
<ul data-role="listview"></ul>
</div>
<div data-role="collapsible" data-collapsed="true" data-mini="true">
<h2>Title #2</h2>
<ul data-role="listview"></ul>
</div>
</div>
I want to be able to when a user clicks on the "toggle" fire of an AJAX call to get content from the server and place it in the correct ul. I can figure out how to do everything except intercept the "click". I have tried binding on both click and expand on the div's, h2's and even ul's.
I am looking for something like:
$('#test h2').live('click',function() {
// do my AJAX call here to get li's to put in correct ul (assuming none exist)
});
Surely I am missing something super simple.

Ok...Here is a working example (minus the AJAX). The biggest drawback is that this only "fires" on expand. But by then it has already expanded and thus currently shows a blank space. What is really needed is a "before expanding" or "click" event so that you can inject the content you want and then the default can happen (changing icons, showing, etc). Not sure how to go about proposing that...
http://jsfiddle.net/mfumm/
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.css"/>
<script src="http://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js"></script>
<div data-role="page" id="page">
<div id="set" data-role="collapsible-set" data-inset="false"></div>
</div>
$("#set div:jqmData(role='collapsible')").each(function () {
$(this).bind('expand', function() {
if($(this).find('li').length < 1) {
// do ajax call here to get data
$(this).find('ul').append(items).listview('refresh');
}
});
});
$('#page #set li').live('click',function () {
alert('Go to item');
});

Related

Use external panel from dynamically injected page

A new thing in version 1.4.0 alpha 2 of jQuery-Mobile is that panels no longer have to be inside the page that uses them. Instead, external panels can be siblings to the pages.
This works fine with static pages:
<div id="panel" data-role="panel" data-theme="b" data-position="left"
data-display="push">
<h3>This is a panel</h3>
</div>
<div data-role="page" id="staticPage">
<div data-role="header" data-position="fixed">
Panel
<h1>Static page</h1>
</div>
<div data-role="content">
<div class="content-primary">
Go to dynamic page
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function () {
$('#panel').panel();
});
</script>
However, when I generate and inject a page dynamically, the link to the panel no longer works as it is supposed to:
<script type="text/x-template" id="dynamicPageTemplate">
<div data-role="page" id="staticPage">
<div data-role="header" data-position="fixed">
Panel
<h1>Dynamic page</h1>
</div>
<div data-role="content">
<div class="content-primary">
<a href="#staticPage" data-role="button" data-inline="true">
Go to static page
</a>
</div>
</div>
</div>
</script>
<script type="text/javascript">
$(document).bind("pagebeforechange", function (e, data) {
if (typeof data.toPage === "string") {
var url = $.mobile.path.parseUrl(data.toPage);
if (url.hash.search(/^#dynamicPage$/) !== -1) {
$('#dynamicPage').remove();
var template = $("#dynamicPageTemplate").html();
var $page = $(template);
$page.attr('id', 'dynamicPage');
$('body').append($page);
$page.page();
$.mobile.changePage($page, {changeHash: false});
e.preventDefault();
}
}
});
</script>
When I click the "Panel" button in header of the dynamic page, the URL changes to …#panel and nothing is shown. I suspect that jQuery-Mobile tries to show the panel as a page rather than a panel. Am I doing something wrong, or is this a bug?
Fiddle with complete example
jQuery Mobile 1.4 panel (and a lot of other widgets) implementation still don't work correctly. Several new components are not even implemented yet. Not to mention, demo site was not updated since they announced alpha version 1.
Let me get back to pane implementation. It is still under heavy development. Any panel inner content (except buttons) is not properly styled. Just add a listview and see a final result.
Only thing you can do is wait for RC1 versions, or maybe just maybe first beta version (but I wouldn't hold my breath for the beta release).

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