AjaxGetContent - dynamic AJAX website
Recently, we can observe a growing popularity of the use of AJAX technology. It is used not only for dynamic form handling and validation. We can also find whole websites based on dynamic content fetching, without need of full content reload.
Most of these websites has two basic disadvantages: their content cannot be indexed properly by search engine robots, usually they also don't maintain browser navigation buttons functionality (back / next) and linking.
To avoid mentioned drawbacks, we created jQuery plugin - AjaxGetContent.
It allows to transform a classic, standard website into dynamic, ultrafast web page based on AJAX calls, maintaining full content visibility for search engines and browser navigation buttons functions. All links can be opened in new window or copied to clipboard. The browser adress bar is being updated with working links. Additionally, all subpages are cached - when visited once, do not load from server again.
The best sample is our website you are actually browsing - click some links, to see how it works (or see: Twój Skarbiec, Panorama Smaku, PTChPRiE, Finestra).
Core concepts
Our plugin is very simple. We install it for a normal, standard website. Plugin automatically handles click event for all links. After clicking any of them:
- current browser url addres is modified, using dynamic history change or, if not possible (Internet Explorer), by creating a bookmark from the target address (e.g. www.implico.pl/#subpage.html); thanks to this modification, browser navigation buttons will work properly
- callback function onSend is invoked; it can, for instance, start an animation to fade out current content and/or show a preloader
- an AJAX call is sent to the target address, with an additional parameter (defaults to "ajax_get_standard_content"), in order to get content for the subpage
- then, callback function onReceive is invoked, which should handle (insert) received content and finish eventual animations started by onSend function
Installation
Plugin requires jQuery BBQ (Back Button & Query Library), available at http://benalman.com/projects/jquery-bbq-plugin/.
First step is to include JavaScript files, for example in this way:
<script type="text/javascript" src="js/jquery.ajaxGetContent.js"></script>
The file includes BBQ library.
Next, we have to run plugin in the content template and set configuration parameters:
$('link_selectors').ajaxGetContent( {
config_par1 : value1,
config_par2 : value2,
//...and so on...
});
Important: the above code should be run for each of loaded subpage (every time the content is called through AJAX), so that handling can be launched for each link. It should be placed inline (if you use Smarty templates, you can use {strip} tags to minify the code size) or in a separate JavaScript file within a function, called each time the content is reloaded.
Configuration
Here is the list of available options:
Parameter | Default value | Description | |
---|---|---|---|
requestParameter | "ajax_get_standard_content" | Parameter added to each AJAX call to get subpage content. | |
baseUrl | "" (no address control) | Applies only to bookmark linking (IE). Defines base URL, e.g. "http://www.implico.pl/". Used to check if the current address has always form: "www.domain/#subpage.html". In other case, e.g. www.domain/subpage.html, page is reloaded. | |
useCache | true | For true, already visited content is cached; when a subpage is visited again, content is not received from server, but taken from cache. | |
forceBookmarkLinking | false | Forces bookmark-style linking (used for IE <= 9). |
|
params | {} |
Additional parameters. Object:
For elements matching specified selector, specified GET parameters are added to the AJAX call. See section about additional parameters sample usage below. |
|
excludeAttr | { 'rel' : 'lightbox', 'rel' : 'nofollow' } | Object containing element attributes, when detected no AJAX call is performed. By default, these are lightbox and nofollow links. | |
onHrefCheck | (addresses permitted by default: ending with "/" or ".html" or ".php") |
Function which validates address of each link. As arguments there are 2 variables passed: href - link addres and hrefParams - eventual GET query (with leading "?"). Function should return true if address is correct or false, when AJAX call should be blocked. |
|
onElementCheck | (by default links having "no-ajax-load" class or rel="nofollow" attribute are skipped) |
Function tests clicked link element, argument passed is the jQuery object. Returns true if the link should be processed. | |
|
(handle all get forms) |
Specifies the get forms handled automatically by the plugin. An object defined as follows:
For the form identified by the specified selector, callback_function is fired (eventually inline onsubmit code is executed before). If it returns a positive value, the form is serialized into a get query string and current address is modified. To disable this functionality, set the value to null. |
|
formsPost | null (no post forms handling) | Specifies the post forms handled automatically by the plugin. An object defined as follows:
For the form identified by the specified selector, onSend function is fired (eventually inline onsubmit code is executed before). If it returns a positive value, the form is serialized and sent using jQuery.ajax() function. OnReceive function is set as success and error callback. |
|
onSend |
|
Function called right before performing AJAX call. Should be used, for instance, to start an animation or other effects run while content is being loaded. | |
onReceive |
|
Function called after content is loaded by AJAX call. Arguments: data - received content, status - state passed by $.ajax() function ('success' when ok). |
Auxiliary functions
There are four available functions:
- $.fn.ajaxGetContent.clearCache()
Clears cache (when useCache parameter is set to true). - $.fn.ajaxGetContent.load(url)
Forces a specified address to load. When url = null, current page is reloaded . - $.fn.ajaxGetContent.getCurrentUrl(full)
Returns current, called address, e.g. "/subpage.html". Helpful while submitting subpage to Google Analytics (see example below). When parameter full = true, in the case of using pushState function returns full address (with protocol and domain name). - $.fn.ajaxGetContent.scrollTo(id, always)
Scrolls content to the level of element with specified selector. Only direction from bottom to top, if always = true, also scrolls in direction top to bottom.
Basic example
Below we present a sample plugin configuration. It is a limited version of configuration for our home website, which you are browsing right now.
$(function()
{
$('a').ajaxGetContent( {
//basic URL
baseUrl : 'http://www.implico.pl/',
onSend : function(url)
{
//set low opacity for content while AJAX call is performed
$('#ajax-load-area').css('opacity', 0.5);
},
onReceive : function(data, status)
{
data = $($.parseHTML(data, document, true));
//for jQuery < 1.9: data = $(data);
if (status == 'success')
{
//insertion of received content
$($.parseHTML(data, document, true));
//scroll to top
$.fn.ajaxGetContent.scrollTo('#head');
//initialization of scripts, e.g. slider
initAllScripts();
//Google Analytics - add current subpage to statistics
if (window._gaq)
_gaq.push(['_trackPageview', $.fn.ajaxGetContent.getCurrentUrl()]);
}
//restore opacity for content
$('#ajax-load-area').css('opacity', 1);
}
});
});
Server-side
This is probably most problematic question, you will have to deal with when integrating website with our plugin. For each call with configuration parameter requestParameter (defaults to "ajax_get_standard_content"), system should return only this part of content, which changes according to specific subpage. In our sample, this is the content of element with id "ajax-load-area", located between the main menu and footer.
Our plugin is fully compatible with our self-developed system implicoCMS, we haven't attempted to integrate it with any other system. In case of implicoCMS, integrating the plugin with a ready, standard website takes less than 10 minutes. When "ajax_get_standard_content" parameter is detected, only templates with individual content for a subpage are loaded and returned.
Naturally, it is possible to ignore requestParameter parameter and return always whole content of the page, and then insert only the content of "body" element. It is, hovewer, a very inefficient way, though will make the page work faster.
We invite you to integrate and test the plugin with popular, existing CMS systems. We will publish every notices, instructions or suggestions sent to us.
Example: dynamic main menu
Sometimes we can meet a situation, when individual content for each subpage doesn't have a form of a compact area. For example, current section in main menu can be highlighted, just like at our homepage. The solution is very simple. You should attach main menu content to the returned content, then find this element, insert into proper place, and then remove it. Sample (according to the basic example):
(...)
if (status == 'success')
{
//get the element containing main menu and insert it to the proper element
$('.head-menu').html(data.find('.head-menu').html());
//remove main menu element from content
data.find('.head-menu').remove();
//content insertion - without main menu
$('#ajax-load-area').html(data);
(...)
Example: using additional parameters - handle "back" link
Sample use of configuration parameter params is a situation, when we have to make a "back" link to a page with pagination. For instance, you can find it in our Portfolio section. Let's assume, that we click a project link, being at the second page of the results. Under project description we can find a "back" link, which should lead to the second page of portfolio projects. To tell the script which prepares the "back" link, that it should return to the second page of results, we should add the following configuration code in a template preparing content for the second page of portfolio projects:
(...)
$('a').ajaxGetContent( {
'params' : {
'.project-item a' : {
'ajax_get_standard_content_back_page' : 2
}
},
(...)
Where "project-item" is the container for each project brief on the list.
In a server-side script, we should use the parameter "ajax_get_standard_content_back_page" to create the proper "back" button, leading to the second page of results, as you can observe at our website.
Demo page
We have prepared a fully functional, sample website:
Requirements: Apache server with htaccess support (or emulator), PHP interpreter.
Examples of usage
We have successfully used the plugin in the following projects:
- www.panorama-smaku.pl (restaurant)
- www.ptchprie.pl (Polish Plastic and Aesthetical Surgeons Society)
- www.finestra.pl (window manufacturer)
- www.boone.pl (clothes brand)
- www.klin-winter.pl (wholesaler of household goods)
- www.sportolimp.pl (wholesaler of sport goods)
- www.apartament-lublin.pl (apartments for rent)
Sent by our readers:
- csgames.pl (by: Mirosław Święcicki)
Compatibility
The plugin runs properly in all major browsers, including IE from version 6, and in mobile devices.
Changelog
The following versions were published:
- Version 1.4 - automatic get/post form handling, included BBQ library in source file
- Version 1.3.3 - fixed bookmark (anchor) handling
- Version 1.3.1 - critical fix: added Android popstate event bug handling
- Version 1.3: clearCache function, removed excludeSelector and excludeUrl config parameters - added onElementCheck parameter instead, automatic firing of hashchange event for IE<10
- Version 1.2: popstate-based linking (in opposition to bookmark linking), middle-click bug fixed
- Version 1.1: cache introduced
- Version 1.0: bookmark-based linking
Licensing
The plugin is published under the MIT license.
Download
In the section below you can download essential files:
- AjaxGetContent plugin, version 1.4
- AjaxGetContent plugin, version 1.4 (minified)
- BBQ Library (required but embedded in plugin code) - modified for jQuery 1.9+ compatibility
- jQuery Library (required)
You can also visit our account at GitHub and jQuery Plugin Registry.
Article coming up next month - "Params class. Easy multiple arguments handling in PHP". We invite you to follow our publications.