Delaying load of page contents until menu item clicked in a multi-page template - jquery-mobile

I'm not sure I understand what's possible with multi-page templates in JQM so I need a bit of help. I'm using version 1.4.5.
Let's say my app has only two pages (Page A and B) generated by a multi-page template. It takes the server several seconds to generate each page because they require many database calls and data processing. Currently, this multi-page template is generated by a single script on the server, index.pl.
Both pages are accessed by the user through a navbar. Page A is the first page in the template so it's visible to the user first.
To speed up the app, I want the HTML for Page B to get generated and fetched from the server only after the user taps the navbar menu item for Page B.
After Page B loads, the user should now be able to switch between pages instantly since the content for both pages are loaded into the DOM.
What is the proper way of accomplishing this desired result?
Do I tie the navbar tap on Page B to an ajax call and inject the server response into Page B? This seems kludgy.
I'm thinking I'm missing something fundamental about JQM but I'm not sure what. Can someone help?
SERVER-SIDE SCRIPT PSEUDOCODE:
<!-- PAGE A -->
output <div data-role="page" id="page_a">
output <div data-role="navbar">
output <ul><li>Page A</li>Page B<li></ul>
output </div>
output <div role="main" class="ui-content">
generate_html_page_a();
output </div>
output </div>
<!-- PAGE B -->
output <div data-role="page" id="page_b">
output <div data-role="navbar">
output <ul><li>Page A</li>Page B<li></ul>
output </div>
output <div role="main" class="ui-content">
generate_html_page_b();
output </div>
output </div>

For your architecture the best approach is single page template but you can use the pagecontainer API to load any page programmatically.
$(":mobile-pagecontainer").pagecontainer("load", "about.html", { role: "dialog" });
Check the jQM docs for more information.

Related

Jquery Mobile Javascript not working on ajax load

Have the following markup in my html page to toggle a search bar based on if a search icon is clicked:
<a id="searchIcon" href="/"></a>
<div id="searchWrapOuter" style="display:none;">
<div id="searchWrapInner">
<div id="formContainer">
<form id="searchForm" action="#">
<div>
<input type="search" name="search-mini" id="search-mini" value="" data-mini="true" />
</div>
</form>
</div>
</div>
</div>
Width the following javascipt/jquery:
$(function() {
$(document).on("click", "#searchIcon", function () {
var searchWrapper = $("#searchWrapOuter");
$(searchWrapper).slideToggle();
return false;
});
});
This code works as expected on a page load direct off a Url. When coming into the page off a link which is Ajax loaded, loads the contents of the page into the DOM, and the DOM ready handler only executes for the first page.
I have read about using the
$(document).on('pageinit'), not $(document).ready()/$(function()
I still haven't been able to get this to work when coming in off an ajax link however. What would be the correct way to implement these events to get the code to work coming in from an Ajax link?
Thanks,
Most likely it is because you are using IDs instead of classes. jQuery Mobile doesn't work well with IDs because it caches pages into the DOM so if you open a page, close it, then go back to the page, you might have your page twice inside the DOM (one visible, one hidden/cached). So when you do $("#searchWrapOuter") you don't know which element you are actually dealing with (in your case, probably the hidden one).
The solution is to change your IDs to classes. This is not very intuitive but I found that is the best way to work with jQuery Mobile.
Also note this comment in the doc which might also be relevant to you:
The id attribute of all your elements must be not only unique on a given page, but also unique across the pages in a site. This is because jQuery Mobile's single-page navigation model allows many different "pages" to be present in the DOM at the same time. This also applies when using a multi-page template, since all "pages" on the template are loaded at once.
http://jquerymobile.com/demos/1.2.0/docs/pages/page-anatomy.html
You can manually adjust delay time to 500ms and 1s.
$(searchWrapper).delay(1000).slideToggle();
My issue is that the page id was below the pages tags. So once I moved the page div above it, the javascript was included in the ajax page load. Previous to this

jquery mobile changePage break tabs in footer

I have a JQuery Mobile app with two pages: page1 and page2
On page1, I am redirecting the user to page2 via the following code:
$.mobile.changePage("/home/page2/", { transition: "slide" });
Page2 has three data-role="page" elements in it. Each of these pages has the following in the footer:
<div data-role="footer" data-position="fixed">
<div data-role="navbar">
<ul>
<li>Screen 1</li>
<li>Screen 2</li>
<li>Screen 3</li>
</ul>
</div>
</div>
If I navigate directly to /home/page2 the tabs work fine. However, when I redirect the user to page2 via changePage(), the tabs do not work. What would cause this?
From the jQuery Mobile documentation:
Linking within a multi-page document
It's important to note that if you are linking from a mobile page that
was loaded via Ajax to a page that contains multiple internal pages,
you need to add a rel="external" or data-ajax="false" to the link.
This tells the framework to do a full page reload to clear out the
Ajax hash in the URL. This is critical because Ajax pages use the hash
(#) to track the Ajax history, while multiple internal pages use the
hash to indicate internal pages so there will be conflicts in the hash
between these two modes.
changePage() inherently uses Ajax to load the page and that is the cause of your problem, because only #screen1 gets loaded.
If your app UI and logic allow you make your redirect from Page1 to Page2 with a link:
Go to Page 2
If you have to redirect programmatically consider splitting the multipage Page2 into separate JQM pages (e.g. page21.html, page22.html, page23.html) and link them appropriately or produce your content dynamically when user clicks on navbar tabs.

ASP.Net MVC3 and jQuery UI Tabs

I have created a HTML layout below with jQuery UI tabs
All the tab information are related to Employee
HTML Code:
<div id="tabs">
<ul>
<li>Details</li>
<li>Deparment</li>
<li>Salary Info</li>
</ul>
<div id="tabs-1">
<p>Some fiels here</p>
</div>
<div id="tabs-2">
<p>Some fiels here</p>
</div>
<div id="tabs-3">
<p>Some fiels here</p>
</div>
</div>
All i need is i want to keep this in MVC page.
Can i have all tabs in one View or i can use #Html.Partial? or PartialViewResult? for each tab.
Some time the user may update only Department information. Here i should save only that tab information.
I want all these tabs loaded at first time and not in on demand using ajax.
Can anyone suggest how can i organize my need in MVC?
Note: Also another thing is i want to use the same for Add and Edit employee. In case of Add Employee i should able to view only Basic Detail as enabled and other tabs in disabled mode. Once the user save basic detail other tab should get enabled.
View fragmentation:
You can do either single view, or split it on multiple partials. It doesn't really matter till they render necessary html.
To save information from each tab separately, wrap each tab content in <form />, so you'll have multiple forms instead of one.
To show next tab on submit, solution will depend on submit process. If you have synchronous Post(Get) then you'll have to pass pass tab parameter with Response and depend on response open next tab on DOM ready (use jQuery for that). Otherwise, if you submit tabs with ajax, you may switch tab in your handler.

Close button on dialog returns to the wrong page

Here's a very simple fiddle:
http://jsfiddle.net/mmSKj/
If you click the "presets" button in the header bar, it opens a dialog. If you click the "close" button on the dialog, instead of going back to the page it came from, it goes to the last page (excluding the dialog itself) on the page (the one with the content This is another page). How come? Is there a way to fix the automatically inserted back button so it behaves itself properly (like the "home" button I included in the dialog) or, failing that, is there a way to remove the close button.
<div data-role="page" id="index">
<header data-role="header">
<h1>Index</h1>
Presets
</header>
<article data-role="content">
<div>This is the main page</div>
</article>
</div>
<div data-role="page">
This is another page
</div>
<div data-role="page" id="presets">
<header data-role="header">
<h1>Presets</h1>
</header>
<div data-role="content">
This is a dialog!
</div>
</div>
Update
As Taifun pointed out, the problem is the lack of an id on the page. Adding an id fixes my first fiddle. However, my real situation is a little more complicated, as shown in this fiddle:
http://jsfiddle.net/mmSKj/2/
Here I am actually creating pages dynamically using knockout, and I assign IDs to those pages via data binding, but, it seems, those ids are not recognized by jQuery Mobile for some reason. If you look with Firebug, you can see that the ids are correctly added to the attributes of the pages, but when you close the dialog, you end up on page 3 rather than the original page.
Update 2
Simple fix, I just added a dummy id to the bit of html that knockout is going to use as a template:
<!-- ko foreach: pages -->
<div data-role="page" data-bind="attr: {id: name}" id="dummy">
This is <span data-bind="text:name"></span>
</div>
<!-- /ko -->
See here.
The dummy id is replaced by knockout, so links to that page work correctly and jQuery mobile seems to be happy!
add an id to your other page
<div data-role="page" id="anotherpage">
This is another page
</div>
then it will work, see jsfiddle
coming back to another solution, because you mentioned: is there a way to remove the close button? Yes, just add this style, see also this answer...
<style>
.ui-dialog .ui-header a[data-icon=delete] {
display: none;
}
</style>
and another jsfiddle to demonstrate that

Dynamic navbar not enhanced on first page of multi-page document

I'm dynamically creating the navbar in my multi-page document. My problem is that the navbar is not enhanced on the first page in the document, but - strangely - on every other page. The kicker is that if I add a page in the code before this actual first page and set up an event to forward to the "actual" first page, everything works fine. The code for the navbar is the same everywhere for now:
<div data-role="page" id="stdPage" data-theme="b">
<div data-role="content">
...
</div><!-- /content -->
<div data-role="footer" data-position="fixed" data-id="persFooter">
<div data-role="navbar">
<ul>
<li></li>
</ul>
</div><!-- /navbar -->
</div><!-- /footer -->
</div>
I'm populating the navbar on all the pages using:
$(function () {
$("div[data-role='navbar'] ul").empty();
$("div[data-role='navbar'] ul").append("<li>Test</li>");
$("div[data-role='navbar']").navbar();
});
When doing this, as I said, the navbar on the first page - the one already on display - is not enhanced. All the other pages have enhanced navbars.
I've tried messing around with .page() and trigger("pagecreate") etc. to no avail.
Any help would be greatly appreaciated.
The problem is that your navbar needs to be in the page when the 'pageinit' event fires the first time your browswer loads that page. This is when jQ Mobile enhances the content of your page.
It sounds like you're adding the navbars to your whole document after the 'pageinit' event fires on your first page. This is why when you navigate to any other page, it fires 'pageinit' and enhances your content properly.
What you should try is copying your common header on the 'mobileinit' event, copying it before jQuery mobile loads (put the script you're using before the jQ Mobile script tag), or put your header's markup on your first page and copy clones (.clone()) to everypage after the markup is enhanced.
As for the trigger the proper syntax is this: $(yourelement).trigger('create').
$(function () {
$("div[data-role='navbar'] ul").empty();
$("div[data-role='navbar'] ul").append("<li>Test</li>");
$("div[data-role='navbar']").trigger('create');
});
Good luck!
FOLLOW UP: Here's how I did it.
I had a header that I wanted to make common to certain pages on of which was my first page. So I made the header on that front page as I normally would. On my other pages I put a placeholder div with a class="commonHeader".
Then on 'mobileinit' I added the following instruction:
$(document).on('mobileinit', function(event){
$('.commonHeader').each(function(index, element) { //attach common header to all pages
$(element).replaceWith($('#frontPage [data-role="header"]').clone(true, true));
});
});
You can try using the same method only on the pages you need common header.

Resources