I'm doing some tests with jQuery Mobile and trying to figure out how to setup an application and its various pages. Ideally, I would like the framework to load the pages with transitions but still keep each pages clearly separated. In particular, it seems that a page loaded via Ajax doesn't "clear" the JavaScript or CSS of the previous page:
Example 1 - JavaScript
For instance, if I have something like this in page1.html:
<script>
setInterval(function() {
console.info('Interval' + (new Date()));
}, 1000);
</script>
Then if I load page2.html, the interval is still running. If I go back to page1, a new interval is started so there are now two intervals running, and 3 and 4, etc. every time I go back to page1.
Example 2 - CSS
Another issue is with styling. Let's say two developers, working independently on two different pages, create an element my-element. In page1, this element is styled:
<style>
#my-element {
color: red;
}
</style>
<span id="my-element">This one is red</span>
in page2, the element is not styled:
<span id="my-element">This one has no style</span>
Again, if I go to page1.html first and then page2.html, my-element ends up being red, even though it wasn't styled in page2.html.
So I guess I have two questions:
Currently it seems that jQuery Mobile approach to loading pages is not scalable at all. CSS, JS created on one page, carry on to the next. So is there any way to make jQuery Mobile load pages "cleanly". i.e. completely deleting everything from the previous page so that bits of JS or CSS don't affect the next page?
If not, what is the correct way to work with multiple pages, in a scalable way, in jQuery Mobile?
the behavior you are describing is what makes JQM work. your DOM persists (including js and css of the first page you load), until you load a page using 'data-ajax=false' or 'rel=external' which will do a regular page load (no ajax).
By loading the page via ajax you will mostly have at least two pages in the DOM - the page you started on (like an anchor page) and any other page you are loading via ajax (which gets removed once the next page is loaded).
this approach allows to have transitions and other functions which you can share across pages.
still you can easily target specific pages with js/css. I'm always runnimg a controller.js file in my applications, which handles page specific things by binding to any of the JQM events (pagebeforeshow, pageshow...). Likewise for page specific css, just use the page id attribute to make css page specific.
Related
Many aspects of my site are dynamic. I am using jquery.
I have a div which once the DOM is ready is populated using load().
Then if a button is clicked, using load() once again, this value is replaced by another value.
This kind of setup is common across my site. My homepage is essentially lots of dynamically loaded, refreshed, and changeable content.
What are the repercussions of this for SEO?
Ive seen sites where each page is loaded using load() and then displayed using the animation functions... It looks awesome !
People have posed this question before, but noone has answered it properly.
So any ideas? JQUERY AND SEO??
Thanks
EDIT
Very interesting points. I dont want to overdo my site with jaascript.. just where neccesary to make it look good - my homepage however is one place of concern.
So when the DOM is readY, it loads content into a div. On clicking a tab, this content is changed. I.E No JS, No content.
The beauty here for me is that, there is no duplicated code. Is the suggestion here that i should simply 'print' some default content, then have the tabs link to pages (with the same content) if JS is disabled. I.E sacrifice a little duplicate code for SEO?
As far as degrading goes, my only other place of concern is tabs on the same page.. I have 3 divs, all containing content. On this page two divs are hidden until a tab is clicked. I used this method first before i started playing with JS. Would it perhaps be best to load() these tabs, then have the tab buttons link to where the content is pulled from?
Thanks
None of the content loaded via JavaScript will be crawled.
The common and correct approach is to use Progressive Enhancement: all links should be normal <a href="..."> to actual pages so that your site "makes sense" to a search spider; and the click() event overrides the normal functionality with load() so normal users with JavaScript enabled will see the "enhanced" version of your site.
If your content is navigable when JavaScript is turned off, you'll be a good ways toward being visible to search engines.
Note that search engine crawlers won't be submitting any forms on your site, so if you have any or elements that are meant to be navigating between your site's content pages, that content is not navigable by search engines.
Here is a guidelines how to make Google to crawl content loaded with ajax: http://code.google.com/web/ajaxcrawling/docs/getting-started.html
I use jquery load() asynchronous page load. It greatly improves user experience, but not seo-friendly. Here's the only solution I have found so far:
On first load I do not use jquery load() and try to write cookie with javascript.document.cookie = 'checkjs=on';
On next page load if php script finds this cookie it means that javascript is enabled and jquery load() can be used. If there's no such cookie then javascript is off (probably spider came), so jquery load() is not used.
if (!$_COOKIE['checkjs'] || $_COOKIE['checkjs']!='on'){echo 'js is off, hello Google!'; } else {echo 'js is on, can use jquery load';}
This way I can be sure that most of users can benefit from asynchronous page blocks load, exept for the very first load. And spiders get all content too.
In your case you could just load the same page with new parameter that makes another tab active. Spider is gonna be happy.
I wanted to know if there was any way to control browser painting, for example I'd like to load elements at the top of the page first so users can see content straightaway. The elements at the bottom of the page can load last as the user will not see them until they scroll down.
I'm looking to optimize my site which currently has a 6 second load time and I'd like to get it down to 1 second. This is mostly being caused by JS and images. I know that reducing both these will mean I wont need to worry about directing the painting but out of interest I just wanted to know if it was possible?
Apologies if my understanding of browser painting is very basic
its not that difficult. all you need is ajax. load the inital markup and then load the rest of the page via ajax.
just load the page with little markup which you initally want to show to the user. then as user scrolls down you can make ajax calls and get xml or json or also html files and render them on you page, for example:
$(window).on( "scroll" , function() {
var $document = $(document);
var $window = $(this);
if( $document.scrollTop() >= $document.height() - $window.height() - 400 ) {
//make ajax call here and load the data
}
});
Also read this
After looking into this further I found this article
http://www.feedthebot.com/pagespeed/prioritize-visible-content.html
which provides a good way of directing which parts of the page are rendered first. By separating your content in to above and below the fold content you can decide what needs to be delivered first i.e. your main content rather than sidebar ads. Using inline style to display your above-the-fold content will make it appear very quickly since it won't need to wait for for an external request.
But this is only good for simple CSS, if pages require complex CSS then it's better to use an external file because:
"When you use external CSS files the entire file is cached (remembered) by the browser so it doesn't have to take the same steps over and over when a user goes to another page on your website. When you inline your CSS, this does not occur and the CSS is read and acted upon again when a visitor goes to another page of your website. This does not matter if your CSS is small and simple. If your CSS is large and complex, as they often tend to be, then you may want to consider that the caching of your CSS is a better choice."
http://www.feedthebot.com/pagespeed/inline-small-css.html
I have a jQueryMobile application with multiple single-pages, linked together.
Some of these pages use common javascript files. So I currently import those javascripts only within pages that need them. For example:
Page A -> include fileutils.js and has a link to Page B
Page B -> include fileutils.js
The user clicks on Page B from Page A. Is there the risk of importing fileutils.js multiple time and execute its code multiple times too?
Thanks in advance
You don't need to be worry. Let me explain you how jQuery Mobile works.
What you have is called multi HTML page template. In this case only initial HTML can have more then one data-role="page" page inside, every other subsequent page can have only one data-role="page" page inside.
One first page is initialized it is fully loaded into the DOM. That HTML page becomes a skeleton for a future page loading. Because it is fully loaded it can hold more then one data-role="page" page inside.
When next page is initialized jQuery Mobile will strip everything and load only data-role="page" content. Everything else is going to be discarded, including the HEAD content. Even more only first data-role="page" page is going to be loaded, which means you can't have more then one data-role="page" page inside.
This means that if you have a custom javascript inside subsequent pages it must be inside data-role="page" div, otherwise jQuery Mobile will discard it.
This works in case standard AJAX loading is on, which is a default state. If AJAX loading is turned off jQuery Mobile will load pages like they are normal pages and every subsequent page will replace previous page in the DOM.
Regarding your other question, because of this architecture same js files will never initialize more then once. But there's another problem you will need to be careful with event binding. Because of this specific architecture events can be bind more then once. So you will need to use pageinit page event to initialize your javascript per page. There are several more solutions to this problem but I will describe them only if you want.
I have used $.mobile.changepage to do the redirect in my phonegap+jquerymobile projects. However what makes me confused is that I need to put the script of all the pages to the same file index.html. If not, the redirect page can not execute the function in its header.
for example, my index.html seem to be
$(document).bind("deviceready",function(){$.mobile.changepage("test.html");})
then, my device will redirect to test.html which seem to be
$("#btnTest").click(function(){alert("123");})
<button id="btnTest">Test</button>
However, the script will never execute in test.html. Then I put the script to index.html, what I expect to be is done. Whatever, if I put all the script to the same page, the project will become harder and harder to be preserved. Appreciated for your help.
Intro
This article can also be found HERE as a part of my blog.
How jQuery Mobile handles page changes
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 button is show successfully but click event is not working. Same click event whose parent HEAD was disregarded during the page transition.
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).
Solution 1
In your second page, and every other page, move your SCRIPT tag into the BODY content, like this:
<body>
<div data-role="page">
// And rest of your HTML content
<script>
// Your javascript will go here
</script>
</div>
</body>
This is a quick solution but still an ugly one.
Working example can be found in my other answer here: Pageshow not triggered after changepage
Another working example: Page loaded differently with jQuery-mobile transition
Solution 2
Move all of your javascript into the original first HTML. Collect everything and put it inside a single js file, into a HEAD. Initialize it after jQuery Mobile has been loaded.
<head>
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; minimum-scale=1.0; user-scalable=no; target-densityDpi=device-dpi"/>
<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>
<script src="index.js"></script> // Put your code into a new file
</head>
In the end I will describe why this is a part of a good solution.
Solution 3
Use rel="external" in your buttons and every elements you are using to change page. Because of it ajax is not going to be used for page loading and your jQuery Mobile app will behave like a normal web application. Unfortunately this is not a good solution in your case. Phonegap should never work as a normal web app.
Next
Official documentation, look for a chapter: Linking without Ajax
Realistic solution
Realistic solution would use Solution 2. But unlike solution 2, I would use that same index.js file and initialize it inside a HEAD of every possible other page.
Now you can ask me WHY?
Phonegap like jQuery Mobile is buggy, and sooner or later there's going to be an error and your app will fail (including loaded DOM) if your every js content is inside a single HTML file. DOM could be erased and Phonegap will refresh your current page. If that page don't have javascript that it will not work until it is restarted.
Final words
This problem can be easily fixed with a good page architecture. If anyone is interested I have wrote an ARTICLE about good jQuery Mobile page architecture. In a nut shell I am discussing that knowledge of how jQuery Mobile works is the most important thing you need to know before you can successfully create you first app.
Unlike normal ordinary HTML pages, jQuery Mobile uses ajax technology when navigating between pages. So make sure to import all your JS files and libraries in all your html pages.
If you notice closely you will see that JS files from previous page is taken into consideration when loading the second page. But if you force rrefresh the current page then the js files of the current page will be effective.
So as I said earlier make sure to import the js files in all the html files.
Also no need to call deviceready, use following syntax to call your page specific js functions
$(document).on('pageshow', '#YourPageID', function(){
// Your code goes here
});
Jquery Mobile uses ajax to load a "page". A "page" here is a div with data-role=page. If you load a physical page index.html, you can navigate using changePage to any "page" div inside that page.
However, if you want to load a "page" from other physical page, jQM will only load the first "page" div from that page. What actually happen is you do not change page, jQM just load that particular "page" div using ajax and inject it to your current page.
You have two possible architecture where you put all your "pages" in a html page and navigate from there. Or you can have multiple page architecture. You can always mix this.
To physically change page, you need to add rel=external to your link.
I am using jquery ajax to load content from one page into a div on the current one, similar to the way gmail switches between inbox, trash, etc. I am using jQuery's load method
$("#divGlobal").load("newPage.html #container");
to load the content I need into my div.
newpage.html #container also has associated javascript & css files associated with it. Right now I am loading them by appending the necessary <script> and <link> tags to <head> but it does not always work. The files always load (I am watching XHR info in Firefox) but do not always seem to work correctly.
For instance, if I load page1.html & associated files (including jQuery functions for UI), everything works fine. However, if I then load page2.html and go back to page1.html, the files load but the jQuery functions are not responding.
Is there a better way of loading javascript & css files associated with the content I am loading?
Reloading the same javascript that you have previously loaded may not do what you want because all the variables and functions are already defined from the previous load and some state may already be in place from the previous load. Loading it again into the same page doesn't start from scratch which is probably what you want.
If you control the pages you're loading, then you can write the javascript in a way that will work by just having the scripts in the content load specifically designed so that they set the state exactly how you want it and clean up any previously loaded state, but you would have to write them that way in order to work that way. This would include resetting any DOM modifications, event handlers, global variables, etc... that the first invocation of the script may have modified.