Using Ajax with Joomla and Mootools to create a rich and efficient popup user interface

Download

This article uses Joomla version 2.5 though it can be easily adapted for other releases, it also uses the Mootools JavaScript library provided with Joomla to create a modal pop-up box using ajax. JSON messaging would make this more flexible and scalable, but to reduce complexity and focus on the ajax aspect, json is left as an exercise for the reader.

With many tools readily available for creating pop-up windows it's easy to overlook the benefits of creating your own when the need arises.  Customised applications can offer tangible benefits of fitness for purpose, the two live examples below use the techniques in this article in different ways as their presentation requirements are different, they both offer a rich and intuitive interface that uses fewer server resources than if each page was generated separately.

As with any advanced technique, it is essential to degrade elegantly so when JavaScript is turned off or unavailable the application still delivers the same content in an effective and intuitive way.

From the viewers perspective the application consists of a page of images, which when an image is clicked opens up a pop-up box with a larger image that itself has interactive content inviting more clicks.

The techniques are simple in that the list of images has modal behaviour added, this changes the behaviour of a normal click into an ajax post and it is this ajax post that is dealt with more efficiently.  When the view receives the request the appropriate content is returned.

The parts that integrate to make this work are
- Framework
  - Mootools modal framework with initialisation code
- Component
  - one or more click-able links
  - view that delivers either full page or fragment
- Template
  - template that renders just the page fragment

Framework

The version of modal.js may need to be patched (both modal.js and modal-uncompressed.js) at media/system/js by adding the following script at the end.

SqueezeBox.handlers.extend({
	ajax: function(url) {
		var options = this.options.ajaxOptions || {};
		this.asset = new Request.HTML(Object.merge({
			method: 'get',
			evalScripts: false,
				onSuccess: function() {
				this.applyContent(this.asset.response.html);
				if (options.evalScripts !== null && options.evalScripts) Browser.exec(this.asset.response.javascript);
				this.fireEvent('onAjax', [this.asset.response.html, this.asset]);
				this.asset = null;
			}.bind(this),
			onFailure: this.onError.bind(this)
		}, this.options.ajaxOptions));
		this.asset.send.delay(10, this.asset, [{url: url}]);
	}
}); 

Component views

There are two views, a list to show the main items and an item to show an individual item.

List

The default template (views/list/tmpl/default.php)

To include the Mootools modal scripts and initialisation code add the following

JHtml::_('behavior.modal', 'a.lightbox');

The first argument says to load the modal behaviour, the second identifies the mark-up that will be used for the pop-up, in this case an html anchor with class lightbox.

The class name lightbox is a thank you to Lokesh Dhakar http://lokeshdhakar.com/projects/lightbox2/ from which the SqueezeBox Expandable Lightbox was inspired.

$link = JRoute::_( 'index.php?option=com_component&view=item&id='.$item->id, false );
$handler = "{handler: 'ajax',"
. " size: {x: 800, y: 400},"
. " onClose: function() {},"
. " onAjax: function() { SqueezeBox.assign($$('a.lightbox2'), {parse: 'rel'});},"
. " ajaxOptions: {method: 'post'}}"
;

So that the item view can tell the difference between a normal request and an ajax request we will ask the ajax request to use a POST method rather than a GET "ajaxOptions: {method: 'post'}"

The parse: rel in onAjax allows the ajax call to be recursive so the pop-up window can also use ajax to get content, the full onAjax parameter is as follows

onAjax: function() { SqueezeBox.assign($$('a.lightbox2'), {parse: 'rel'});}

Note the naming of the class to lightbox2 so that we don't call lightbox recursively.

Item

The view (views/item/view.html.php) differentiates between a normal request (GET) and an ajax one (POST).  When an ajax post is received, the template is set to component and the view layout to lightbox.

function display($tpl = null)
{
    $this->item = $this->get('Item');
    if ( JRequest::getMethod() == 'POST'){
        JRequest::setVar( 'tmpl', 'component'  );
        $this->setLayout('lightbox');
    }
    parent::display($tpl);
}

The component template renders just the component's output without any of the other aspects that normally make up a page, it is this single aspect that provides the main win-win benefit as the server does less processing and the browser just inserts this fragment into the page without the need for a reload.  The default layout (views/item/tmpl/default.php) is used for rendering normal mark-up for non javascript browsers and search engines, and the lightbox layout (views/item/tmpl/lightbox.php) has similar mark-up tailored to the pop-up box though could be the same if preferred.  As this is an ajax request the functionality provided by Mootools is already available in the page so there is no need to include any additional scripts.

The component output could include

<?php
$rel_handler="{"
	."handler: 'ajax',"
	." size: {x: 800, y: 450},"
	." onClose: function() {},"
	." onAjax: function() {"
	." SqueezeBox.assign($$('a.lightbox2'),"
	." {parse: 'rel'});"
	." },"
	." ajaxOptions: {method: 'post'}"
	."}";
?>
<p><a id='item-<?php echo $item->id ?>'
 class="lightbox"
 href='<?php echo $link ?>'
 rel="<?php echo $rel_handler ?>">
<img src='<?php echo '/images/' . $item->image; ?>' alt='<?php echo $item->title; ?>' />
</a></p>

<?php
    foreach ($this->items as $item)
    {
        $link = JRoute::_( 'index.php?option=com_component&view=item&id='.$item->id, false);?>
<a href='<?php echo $link ?>'
 class="lightbox2"
 rel="<?php echo $rel_handler; ?>"><img
 src='<?php echo '/' . $item->icon_image;?>'
 alt='<?php echo $this->title ?>' /></a>
<?php
    }
?>

Google Analytics Event Tracking

Event Tracking is easily included using Ajax with Mootools, by adding evalScripts: true to the ajaxOptions, any script tags in a response will get evaluated so you can easily add your own or Google Event tracking.

An example ajax handler could be like the following

$rel_handler = "{handler: 'ajax',"
. " size: {x: 800, y: 400},"
. " onClose: function() {},"
. " onAjax: function() {SqueezeBox.assign($$('a.lightbox2'), {parse: 'rel'});},"
. " ajaxOptions: {method: 'post'
, evalScripts: true}}"

An example script tag to include with the ajax response added to views/example/tmpl/lightbox.php

<SCRIPT>_gaq.push(['_trackEvent', 'Videos', 'Play', 'Gone With the Wind']);</SCRIPT>

These ajax events will be included in any Google Analytics reports as normal.

A couple of examples of this technique in action are at http://david-johnson.co.uk/ocean.html and http://kjandrews.co.uk/images-installation.html

By Alan Hicks