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 SkarbiecPanorama SmakuPTChPRiEFinestra).

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:

{
'selector' : { parameter1 : value1... }
}

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
function(href, hrefParams)
{
return (href.length > 0) &&
((href.substr(href.length-1, 1) == '/') ||
(href.substr(href.length-5, 5) == '.html') ||
(href.substr(href.length-4, 4) == '.php'));
}
(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
function(element) {
return
!element.hasClass('no-ajax-load') &&
(element.attr('rel') != 'nofollow');
}
(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.
formsGet
{ 'form[method="get"]' :
function() { return true; } }
(handle all get forms)
Specifies the get forms handled automatically by the plugin. An object defined as follows:
{
  form_selector1 :
    callback_function() {...},
  form_selector2 :
    callback_function() {...},
... }

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:
{
  form_selector1 : {
    onSend : callback() {...},
    onReceive : callback() {...} },
  form_selector2 : {
    onSend : callback() {...},
    onReceive : callback() {...} },
... }

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(url) {}
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(data, status) {}
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:

Sent by our readers:

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:

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.

 

All rights reserved © 2024 by implico.pl

Change language: pl