I would like to use a Panel in a jqm site for my Choose Language component. So that component will need to be present on every page. Here is the setup for a single-page pane
Here's the solution I came up with. I store the panel contents in a hidden div, and defer the jquery mobile initialization. When the document loads, I append the panel contents to each of the (jqm) page elements and then initialize jqm. The only performance hit occurs when the page first loads.
HTML:
<div data-role='page' class='page'>
<div data-role='content'>
<h1>One</h1>
<a href='#nav' data-role='button'>show nav</a>
</div>
</div>
<div data-role='page' class='page'>
<div data-role='content'>
<h1>Two</h1>
<a href='#nav' data-role='button'>show nav</a>
</div>
</div>
<div id='panel-content' style='display:none'>
<div data-role='panel' class='panel-holder' data-position="right" data-display="reveal" id='nav'>
<div data-role="content">
<ul>
<li><a href="#first" data-link="first">first</a></li>
<li><a href="#second" data-link="first">second</a></li>
</ul>
</div>
</div>
</div>
Script:
$.mobile.autoInitializePage = false;
$(document).on("ready" function(evt) {
var panelHtml = $("#panel-content").html();
var pages = $(".page");
for (var i = 0; i < pages.length; i++)
{ //done synchronously so we can initialize jquery mobile after the DOM is all setup
$(pages[i]).append(panelHtml);
}
$("#panel-content").remove(); // this doesn't need to be in the DOM anymore
$.mobile.initializePage();
});
with inspiration from Gajotres and the way AppFramework handles panels I've made this. It works by copying defined panels to the active page, the panels are defined by id in right-panel and left-panel attributes for the page div:
$(document).on('pagebeforeshow', '[data-role="page"]', function(){
// remove unused tmp panels from DOM
$("#tmpRightPanel").remove();
$("#tmpLeftPanel").remove();
// Hide buttons by default (I'm using a static header and footer on every page too)
$("#openRightPanel").css("display", "none");
$("#openLeftPanel").css("display", "none");
// check if right-panel attribute is set on the page
if ($(this).attr("right-panel")) {
// if it is, it should append the defined right-panel to the page
$("#"+$(this).attr("right-panel")).clone().appendTo($(this));
// rename it to tmpRightPanel
$.mobile.activePage.find('#'+$(this).attr("right-panel")).attr("id", "tmpRightPanel");
// make it a panel
$.mobile.activePage.find('#tmpRightPanel').panel();
// make it visible (the original right panel is set to display: none)
$.mobile.activePage.find('#tmpRightPanel').css("display", "block");
// make the button to open the panel visible
$("#openRightPanel").css("display", "block");
}
// same as right-panel above
if ($(this).attr("left-panel")) {
$("#"+$(this).attr("left-panel")).clone().appendTo($(this));
$.mobile.activePage.find('#'+$(this).attr("left-panel")).attr("id", "tmpLeftPanel");
$.mobile.activePage.find('#tmpLeftPanel').panel();
$.mobile.activePage.find('#tmpLeftPanel').css("display","block");
$("#openLeftPanel").css("display", "block");
}
});
// make the open panel buttons clickable
$(document).on('click', '#openRightPanel', function(){
$.mobile.activePage.find('#tmpRightPanel').panel("open");
});
$(document).on('click', '#openLeftPanel', function(){
$.mobile.activePage.find('#tmpLeftPanel').panel("open");
});
Make a page like this:
<div id="main" data-role="page" data-title="Main" right-panel="right-panel" left-panel="left-panel">
<div class="ui-content">
some page
</div>
</div>
and place the panels somewhere outside a page, and hide them like this:
<!-- leftpanel -->
<div data-role="panel" id="left-panel" data-display="push" data-position="left" data-theme="a" style="display:none;">
something something something
</div>
<!-- /leftpanel -->
<!-- rightpanel -->
<div data-role="panel" id="right-panel" data-display="push" data-position="right" data-theme="a" style="display:none;">
something something something
</div>
<!-- /rightpanel -->
I had the same problem and ended using iframe to load the persistent contenent (in my case a sophisticated search form) from a file:
<div data-role="panel" ...>
<div data-role="collapsible" ...>
<h4>Search for Hotel</h4>
<div class="tmbe-sformcontainer">
<iframe class="tmbe-sform" src="sform.html" frameborder="0"></iframe>
...
sform.html sends a message to the main page whenever the user has submitted a search criteria as:
window.parent.postMessage({action:"search",params:criteria},'*');
and the main page captures it like that:
window.onmessage = function (e) {
if (e.data.action == "search") {
var criteria = e.data.params;
loadHotelListPage(criteria);
}
};
I know it is weird, but it works
Your best course of action is to dynamically create a panel for every page.
I made you a working example: http://jsfiddle.net/Gajotres/pZzrk/
$(document).on('pagebeforeshow', '[data-role="page"]', function(){
$('<div>').attr({'id':'mypanel','data-role':'panel'}).appendTo($(this));
$('<a>').attr({'id':'test-btn','data-role':'button'}).html('Click me').appendTo('mypanel');
$.mobile.activePage.find('#mypanel').panel();
$(document).on('click', '#open-panel', function(){
$.mobile.activePage.find('#mypanel').panel("open");
});
});
Few descriptions:
jQuery Mobile developers have stated that in next major version panel widget will no longer need to be part of a page, instead it will be placed in a same level as a page div. So one panel will ne needed. Unfortunately you will need to dynamically create it.
Panel is a new concept introduced in 1.3. So lets hope more tutorials will show up soon. As of your problem, I guess its better you code a panel in each of your pages. You can make changes to your page real time but make sure to call following method as documented in the documentation.
$( "#mypanel" ).trigger( "updatelayout" );
I'm not sure other ways would be feasible.
For panel, and header and footer, I create a template (I use dustjs) for each element. In the pagebeforecreate
event, I append the html into the current page. You have to use pagebeforecreate
event if you want JQM to 'enhance' the html. If you don't care about this, you can use the `pagecreate' event.