Pages not being unloaded from DOM when using index.html - jquery-mobile

I have two very simple pages as below. If I browse to "mysite.com/" the webserver returns the "index.html" content, as is normal. If I then click the "page2" link, jquery mobile loads the 2nd page into the DOM, but doesn't unload the first page from the DOM, although it is hidden (display:none) from view.
I now have 2 <div data-role="page"> elements in the DOM, with only page2 page visible on screen. If I then click the "index" link on page2, jquery mobile unloads page2 from the DOM, and loads the index.html page into a new DOM element. I now have two instances of <div id="index"> in the DOM which is obviously incorrect!
What is going on? I thought I'd ask on here before reporting it as a bug but it seems like a very simple example that is completely broken!
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.css" />
<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
<script src="http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"></script>
</head>
<body>
<div data-role="page" id="index">
Page2
<p>index page</p>
</div>
</body>
</html>
page2.html
<html>
<body>
<div data-role="page" id="page-2">
Index
<p>Page 2</p>
</div>
</body>
</html>
EDIT:
I found a workaround of page2.html linking to rather than "index.html", which prevents the 2nd duplicate loading, but it still seems wrong that the original page loaded is always kept in the DOM.
EDIT 2: This is a known issue https://github.com/jquery/jquery-mobile/issues/4050 - I just didn't manage to find it despite extensive googling before posting this question. I might raise a bug report against their documentation though, because it is highly unexpected behaviour IMO.

This is the default behavior of jQuery Mobile, first landing page is always kept in DOM. It only removes external pages which aren't cached data-dom-cache="true". You will always have two pages in DOM, landing page and active external page.
Nevertheless, if you wish to remove landing page once you navigate to another page, add data-external-page="true" to page div of the landing page. Once it's created pagecreate, flag it for removal .page("bindRemove"). This is the way jQuery Mobile removes external pages.
Note that is fix will work as long as .page() widget isn't removed and replaced by .pagecontainer() widget.
<div data-role="page" id="pageID" data-external-page="true">
$(document).on("pagecreate", "#pageID", function (e) {
$(e.target).page("bindRemove");
});
Demo

I created a test as described in your question with the two files index.html and page2.html and tested with Chrome (version 38.0). I loaded index.html and then navigated to page2.html and then back to index.html. Using Chrome Developer Tools, I then examined the elements in the page and found the following (screen shot):
As we see, there is one instance of the page called index and one instance of the page called page-2 but no duplicates.
I realize that this does not line up with your own results but am offering this is an answer demonstrating that the story works as expected. If we determine a flaw in the logic of this answer, I'll happily delete it.

Related

jquery mobile javascript not being run when sing JQM pageContainer [duplicate]

I am facing a very strange problem where my javascript code does not run the first time the page is loaded. If I reload/refresh the page, the script runs fine.
After some hit-and-trial's I realized that if I remove the jquery.mobile-1.4.3.min.js library from the previous page (which redirects to my current page) then the script is running as expected.
Can anyone please help on why this is occurring and how can I resolve it ?
Update:
On opening the hpme page (which contains the link to the page containing the JS), I can see the following error in console:
Uncaught TypeError: Cannot set property 'mobile' of undefined .
Please note that this home page is basically a simple code with library declarations and html links.
Edit :
I had missed the jQuery lib earlier and hence the Uncaught TypeError.
Now, my libraries are in the following order :
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquerymobile/1.4.3/jquery.mobile.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/jquery-ui.min.js"></script>
<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jquerymobile/1.4.3/jquery.mobile.min.css" />
<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/themes/smoothness/jquery-ui.css" />
Now there are no errors in my console, but still the JS in the next page does not run in the first load. Oddly, if I remove the jquery.mobile-1.4.3.min.js library, the JS works fine.
Single Page Model
jQuery Mobile loads external pages via Ajax; when you have a link to another page, jQM loads first page div <div data-role="page"> in that page and neglects other tags outside that div.
If you have JS code that you want to run in the loaded page, you have to place it inside page div.
<div data-role="page">
<!-- JS code -->
</div>

jQuery datepicker does not work as advertised

Problem: datepicker is not showing up at all. No errors in the console. All files are included and accessible via Firebug.
After spending way too much time trying to get the jQuery UI datepicker to work, and that includes reading through dozens of Google results, I need your help. Not even the simplest, plain, straightforward implementation of the datepicker is working for me.
Current example I'm testing (stripped down to nothing but the datepicker):
<html>
<head>
<meta charset="UTF-8">
<title>DatePicker Test</title>
<!-- JavaScript -->
<script type="text/javascript" src="../js/jquery/jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="../js/jquery/jquery-ui-1.8.19.custom.min.js"></script>
<!--script type="text/javascript" src="../js/jquery/jquery.ui.datepicker.js"></script-->
<!-- Stylesheets -->
<link rel="stylesheet" href="../css/ui-lightness/jquery-ui-1.8.19.custom.css" />
<script type="text/javascript">
$(function() {
$( "#datepicker" ).datepicker();
});
</script>
</head>
<body>
<div><input type="text" id="datepicker" class="hasDatepicker" /></div>
</body>
</html>
This does NOT work. I've downloaded the entire jQuery UI code (jquery-ui-1.8.19.custom.min.js) and tried everything. I've even tried to add a simple datepicker field to the demo HTML page that comes with jQuery UI. Nothing.
Then I downloaded the developer bundle of jQuery UI, and tried just the datepicker.js with jQuery, but even that failed.
So although I get no errors, and I can see my selector in the code and through calling it up from the console, I just get plain old nothing.
Then I've tried numerous CSS modifications that have been posted in several forum posts, moved my JavaScript from the top to the bottom, after the datepicker . . . and all kinds of mutations, but nothing has worked.
Is it me?
Certainly, it's possible for others to use the datepicker plug-in, what am I doing wrong?
Hey so I looked into your issue. I suggest removing the class declaration in the input that helped me. Also make sure your script links are correct. You are currently asking them to pull from a folder that comes before your current page. If the page and css/js folders are in the same directory you can remove the "../" at the front.
<input type="text" id="datepicker" />
A helpful add-on in FireFox are the Web Developer tools
Check out this js fiddle here for a working example. It's pretty similar to what you are doing minus the class on the input field, aswell as in this case the example is using CDN's.
You must have something wrong (maybe a script or css isn't getting sourced).

Why is jquery mobile not rendering all my html or loading javascript?

I have this:
<title>MyMobile</title>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.0/jquery.mobile-1.0.min.css" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" src="http://code.jquery.com/mobile/1.0/jquery.mobile-1.0.min.js"></script>
<title>My Mobile</title>
<style type="text/css">
table { width:100%; }
table caption { text-align:left; }
table thead th { text-align:left; border-bottom-width:1px; border-top-width:1px; }
table th, td { text-align:left; padding:6px;border: inset 1pt}
</style>
If I go to the page manually my table elements look fine. I can see the borders, etc. If I got the page from another mobile page the page loads ok but the table CSS stuff never get applied. No styles. Hit referesh, styled.
What is going on?
Thank you.
edit: not loading my javascript either. refresh. all works again.
edit: does same if I hit the back button to another page. not everything loads.
Whenever you have A tags, JQM by default uses AJAX to load those pages - and then ignores everything but whatever is included inside the div data-role=page element.
You have 3 options:
You can either tell JQM to always disable AJAX (by setting ajaxEnabled to false) and load pages as "normal browsers" do - this will re-load also all javascript includes, stylesheets, etc...
You can include all the different div data-role=page inside ONE .html page, that way JQM will need to load nothing else when navigating between pages
You can still use AJAX and load external files, but then you'll need to include all your code (HTML/CSS/JS) INSIDE the DIV itself. Note that at this option you'll need to attach to different events (pageinit/beforeshow/show/hide) and not $.ready (since JQM will then take care of that and the DOMContentReady is not actually going to fire.
You can read all about this in the documentation
Hope this helps...

Jquerymobile - $.mobile.changepage

I want to open the the .html file from my .js file. So I Used the $.mobile.changePage("file.html"). In the file.html have file.js. But The file.js does not call when the file.html in invoked.
THanks in advance.
first.js
$.mobile.changePage ("file.html");
file.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>jQuery Mobile Framework - Dialog Example</title>
<link rel="stylesheet" href="jquery.mobile-1.0a2.min.css" />
<script src="jquery-1.4.4.min.js"></script>
<script src="jquery.mobile-1.0a2.min.js"></script>
<script src="../Scripts/file.js"/> // Could not imported
<script src="../Scripts/helperArrays.js"/> // Could not imported
<script src="../Scripts/globalVariables.js"/> // Could not imported
</head>
<body>
<div data-role="page">
<div data-role="header" data-nobackbtn="true">
<h1>Vaults</h1>
</div>
<!-- <div data-role="content" data-theme="c" id="contentVault">
Sample Vault
My Vault
</div> -->
<div data-role="content" id="content">
<ul id="listview" data-role="listview" data-inset="true" data-theme="e" data-dividertheme="b">
<li id="listdiv" data-role="list-divider">List of Items</li>
</ul>
</div><!-- /content -->
</div>
</body>
</html>
Please help me..
When jQM loads another page through AJAX it only pulls in anything within your div[data-role="page"] and nothing else, like the head
So you can if you wanted to, include any JS/CSS within this div, the problem is that if this page is accessed multiple times any CSS will accumulate, but the problem is much worse for JS.
You are basically getting every page appended to the DOM, so the JS runs on the entire DOM (every page you loaded) if you use a global selector like $('div.someClass'), even using an ID isn't a perfect solution because if you can link to the same page twice.
For Smaller Sites
I've solved this by moving all the CSS into one file and for JS code that I want to run each time the page is loaded, I bind to the pageinit and pageshow jQM events:
<script type="text/javascript">
$("div:jqmData(role='page'):last").bind('pageinit', function(){
//your code here - $.mobile.activePage not declared
});
$("div:jqmData(role='page'):last").bind('pageshow', function(){
//your code here - $.mobile.activePage works now
});
</script>
The pageinit event runs when the page is loaded, only ever once (after it's loaded it stays in memory if you navigate back to it, even via a back button this isn't fired again), pageshow on the other hand fires everytime the page is shown, even when you navigate back to it via the back button on the browser for example.
The pageinit runs when the DOM is there, the pageshow event is only if you have some code that depends on the DOM being rendered and you need a quick reference to the active page through $.mobile.activePage or some data changed and you need to refresh this back everytime it's shown. For most purposes I only use the pageinit as a document.ready for jQM and bind my events there. Use bind for static elements, and on instead of live for dynamic elements, because live events listen at the document root, you want to listen at the page div.
For Larger Sites
For larger sites there are advantages to binding a live event to any pages and handling types of pages, this way js code isn't loaded more than once.
If you have external js files with say helper functions that you only need once put that in the head of all your pages (if there aren't too many), if you had a very big site you could probably do better by tracking which JS files have been loaded server side.
All this can be avoided by just not using AJAX to load new pages, so think about whether that transition/loading effect is worthwhile
*Here's how I handle large jQM sites: *
bind a live event to all pages/dialogs pageinit and pageshow events:
$(document).on('pageinit pageshow', 'div:jqmData(role="page"), div:jqmData(role="dialog")', function(event){
I reference each page with a name: <div data-role="page" data-mypage="employeelist">
In this live event you can basically have a switch statement for each page "name", and then check event.type for pageinit/pageshow or both and put your code there, then every time a page is created/shown this event will be fired, it knows what page triggered it and then calls the corresponding code
I eventually had too much code, so I built a handler object where each page's js is included in a separate js file and can register handlers with the live event
The drawback is that all your js for your entire site is loaded on the first page the user reaches, but minified even a large site is smaller than jQuery or jQM so this shouldn't be a concern. The advantage is you are no longer loading all your JS for each page through AJAX each time the user navigates to a new page.
*note: now RequireJS can make this even more manageable
Jquery mobile gets pages via AJAX and adds their content to the current page.
I saw some notices about changing the page title to the incoming one, so they are (planning?) accessing the head, but at the moment jquery mobile doesn't seem to load external js when loadin a page.
More importantly - if you use $(document).ready() it will not be triggered, because it was AJAX

loading jquery ui-tab at bottom of html and tab repainting issue

On a particular page, I am using jquery ui tab to tabify my web page. My JavaScripts are placed in external files and loaded at the end of my HTML. On document ready event, the very first thing I do is to call the tabify plugin.
The problem is that the browser has already painted the page at this point, then repaints it once it tabifies the page. So, I get a split-second flickering of the screen. How do I prevent this flickering? I do not want to load JavaScripts in as I am trying to optimize my site per Google PageSpeed/Yahoo YSlow recommendations.
<html>
<body>
....
<script src="tabify.js"></script>
</body>
</html>
tabify.js
$('document').ready(function(){
$("#tabs").tabs();
});
hide the content with css display:none; then use $("#tabs").show().tabs();

Resources