Tutorial 3: Adding Ajax controls to a controller

Posted by Dave Redfern (Writer), Tutorials on 11 Nov 2008 @ 20:46

Getting Started

Please note: xaJax has been removed from the core framework as over version 0.4. It can still be used and re-integrated, however the preferred method for ajax is to use jQuery, Prototype, MooTools or another Javascript library.

This tutorial builds on the work done in tutorials 1 and 2. If you have not done so already, you should review these or at least familiarise youself with what was covered.

In the same manner that tutorial 2 built on the files created with tutorial 1, this tutorial will add functionality to the files from tutorial 2.

In addition you will need the following:

And now on with the tutorial...

Introduction to xaJax

The Scorpio Framework integrates xaJax into the controller layer to handle ajax requests. Alternatives to this approach include using the output type control to send back XML, XHTML or JSON to jQuery, Prototype etc (this is actually used for the tag editor) and is more useful where complex responses are required or if additional processing must be performed on the client side.

xaJax is very effective though for quick ajax functionality, form submission, browsing search results etc. and can be integrated very easily. It is used extensively in the admin system for many of the control applets.

By default, xaJax is not active in the base controller. This is to avoid loading the files if they are not used. At the time of writing, version 0.5 RC1 is currently being distributed, though this will be upgraded to the latest release shortly.

The main difference (in my mind) between xaJax and other approaches is that xaJax is very much focused on modifying the web page, not just returning data. This is seen in the "assign" method where you can target specific elements and manipulate them from the PHP side. This does tightly couple the view to the controller and this is why ajax requests are handled separately - it is more a bonus than a requirement; but as ajax is a web technology this is a useful way of approaching it. If you need to be able to make available the data via other mechanisms, then the output type is the method to use instead of xajax.

This tutorial will add a very basic random comment in place of the comment list on the Guestbook tutorial. This will use some of the basic features.

So what do we need to do to get ajax working?

Enabling xaJax

As previously mentioned xaJax is disabled by default, however a property exists within the mvcControllerBase to hold an instance of the main xaJax object. In larger projects, a custom mvcController would implement the instantiation of xaJax (similar to the admin system), but for this simple example, we will directly enable it in our guestbook controller.

To enable xajax, find the initialise() method within the guestbookController; then add below the parent call the following line:

$this->setXajax(new xajax($this->buildUriPath(self::AJAX_REQUEST_URI)));
$this->addAjaxControls();

This creates and sets the xajax object to handle the ajax requests. The requests are sent to a specific URI path that ends with the constant mvcControllerBase::AJAX_REQUEST_URI. This is handle by the base distributor that is already configured to handle this alternative URIs.

Next we need to inform xajax about the functions that are available to the webpage. This is done by overloading the addAjaxControls() method from mvcControllerBase. For this tutorial we will only add a single function, but you can add as many as you like. It is not recommended to add the entire object, otherwise you may expose methods that should not be executable.

The method we will expose will be a method to generate a random comment from the guestbook:

/**
 * Adds ajax controls to controller
 *
 * @return void
 */
function addAjaxControls() {
	$this->getXajax()->register(XAJAX_FUNCTION, array('randomComment', &$this, 'randomComment'));
}

Next we need to create our method and handle the request.

Handling the xaJax request

Now that xaJax is aware of our method, we need to implement it withint the controller.

Create a new method and give it the same name as we used when registering it in the previous step. Now add the following 2 lines inside this method:

$oResponse = new xajaxResponse();
return $oResponse;

This provides the basics for any xajax method. It will always return an xajax response object and this should be the first thing instantiated.

At this point it is worth noting that the distributor does not attempt to authenticate ajax requests: they are simply dispatched to the controller. This can of course be changed quite easily, but an alternative (as in the case of the admin system) is to add an authentication wrapper to the ajax calls.

Setting up the view and model

With the basics in place, it is time to add our response. In the same manner as tutorial 2, we will add another method to our guestbookView class to return a formatted random comment.

First though, we need to add the xajax script to the view. This should be added to the construct method so that it is always available to the template files. If we miss this out, then xajax will not be enabled as the javascript links will not be generated.

/**
 * @see mvcViewBase::__construct()
 */
function __construct($inController) {
	parent::__construct($inController) ;

	$this->getEngine()->assign("xajaxScript", $this->getController()->getXajax()->getJavascript('/libraries/'));
}

Now we can create our compile method to fetch the actual template, add our data and return the compiled template. The view code looks like the following:

/**
 * Compiles a random comment
 *
 * @return string
 */
function getRandomComment() {
	if ( !$this->isCached($this->getTpl('randomComment', 'guestbook')) ) {   
		$this->getEngine()->assign('oModel', utilityOutputWrapper::wrap($this->getController()->getModel()));   
		$this->getEngine()->assign('oComment', utilityOutputWrapper::wrap($this->getModel()->getRandomComment())); 
    }   
    return $this->compile($this->getTpl('randomComment', 'guestbook'));  
}

The view simply fetches the data from the model using a custom method and defers rendering to the template: 'randomComment'. The model method is implemented as the following within guestbookModel:

/**
 * Returns a random comment
 *
 * @return guestbook
 */
function getRandomComment() {
	$oStmt = dbManager::getInstance()->prepare("SELECT * FROM ".system::getConfig()->getDatabase('tutorials').'.guestbook ORDER BY RAND() LIMIT 1');
	if ( $oStmt->execute() ) {
		$res = $oStmt->fetchAll();
		if ( is_array($res) && count($res) == 1 && isset($res[0]) ) {
			$oObject = new guestbook();
			$oObject->loadFromArray($res[0]);
			return $oObject;
		}
	}
	return new guestbook();
}

Completing the request method

Finally we can now add the response from our view and assign it back to xajax for display in the web browser. This is handled by the method assign() on the xajaxResponse object. This requires the elementID of an ALREADY existing element on the page, the property to modify which in this case is 'innerHTML' (the case IS important!) and finally our data.

The full request code for the controller is then:

/**
 * Returns a random comment block
 *
 * @return xajaxResponse
 */
function randomComment() {
	$oResponse = new xajaxResponse();
	$oView = new guestbookView($this);
	$oResponse->assign('randComment', 'innerHTML', $oView->getRandomComment());
	return $oResponse;
}

The last step is to set-up our view templates.

Adding the ajax functions

The final step is to add the HTML code to use the ajax function. This will be added to the main guestbook.html.tpl file.

First off, the xajaxScript variable needs to be added to the header. This was assigned in the guestbookView as (in Smarty) {$xajaxScript} and this will need placing in between the < head > tags.

Then in the body of the page we need to add our element that will receive the data from the ajax call. This could be hidden by CSS (which would require additional xajax assigns to set the visibility) or for this example, it will just contain some holding text.

The xajax function we assigned in the controller will be available as xajax_TheMethodName. These can be aliased by changing the third parameter in the controller. For more options it is strongly suggested to check out the xajax documentation.

Note the return false; on the ajax call. This is to stop any submissions - even though this is an input button and not a form submit, we do not want a submission to take place.

Finally; create a randomComment.html.tpl template which for this example contains the usual Smarty printr for the object:

{$oComment|printr}

And that's it! All done. Save all the changes and click the button to see a random comment being inserted. Parameters can be passed in either from a form using xajax_values or as actual parameters. So we could add a limit to our random comment and list 2 or 3. The parameter(s) would need to be sanity checked and the appropriate changes made to the controller method to allow for parameters.

Hopefully you can see how easy this is to add with the minimum of effort. The xajax requests can then be made as complex as you need then to be. For example: check out some of the admin code, in particular the mvcDaoController that handles many of the applets through a single interface.

You can download the files from this tutorial as a Zip file.

< Return to article