REVERSEFOLDS
AJAX CakePHP
CakePHP is a wonderful framework. Unfortunately, like a lot of software, documentation is severly lacking. The effort is definitely there, but with an API containing the occassional "Enter description here... unknown_type", it definitely makes things a bit more difficult. Especially for someone who adopted the RTFM mantra many years ago.
For this article, we're going to try and figure out how to get AJAX and cake to work together without having to comb cake's manual, wiki, the bakery, users' sites and tutorials and Google groups.
First things first - you'll need to have cake installed and running.
Next things second - you'll need to get the scriptaculous and prototype libraries. (I haven't tried any other AJAX libraries, but these seem to work just fine for now).
You'll need to place the scriptaculous and prototype files in /app/webroot/js directory.
Now you need to add the following inside the <head> tag of your layout file (/app/views/layout/default.thtml) to make them available:
<?php print $html->charsetTag('UTF-8'); print $javascript->link('prototype'); print $javascript->link('scriptaculous.js?load=effects'); ?>
At this point, you have 2 options - to use the RequestHandler component or not. If you're doing fancier AJAX things, you can check CakePHP's manual on RequestHandler, but to keep things simple, we won't use it.
In your controller's action, you want to add:
// controller file var $helpers = array('Html', 'Javascript', 'Ajax'); function view() { $this->render('layout file', 'ajax'); }
What you want to do next is create a link, but not just any link. You want to enable an ajax link, and to do that you use the ajax helper that comes with cake.
// view file echo $ajax->link('link text', '/controller/action', array('update' => 'div id') );
Styling it
If you want to add a css class to the link, add the undocumented 'class' option as part of the options array.
// view file echo $ajax->link('link text', '/controller/action', array('update' => 'div id', 'class' => 'aclass'));
What about images?
To include an image to be linked rather than text, you simply include the html for the image in place of the first parameter, but be sure to add FALSE so the code doesn't get escaped.echo $ajax->link('<img src="/img/button.gif" border="0"/>', '/controller/action/', array('update' => 'div id'), null, FALSE );
Multiple divs
That's all fine and dandy, but what if you wanted to update more than one div at a time? To do that, you'll need to add an array of divs to update, and also use the $ajax helper to create the divs.echo $ajax->link('link text', 'controller/action', array('update' => array('div1', 'div2')) ); // create the div code rather than hard-coding <div id='div1'> echo $ajax->div('div1'); echo $ajax->divEnd('div1'); echo $ajax->div('div2'); echo $ajax->divEnd('div2');
So it updates. How do I make it look cool?
To add effects, you'll need to add the effect to the link:$ajax->link('link text', 'controller/action', array('update' => 'div id', 'loaded' => 'scriptaculous effect') );
A complete example
We'll create a simple example here to demonstrate.<?php /** * $Id: approot/controllers/things_controller.php */ class ThingsController extends AppController { var $name = 'Things'; var $helpers = array('Html', 'Javascript', 'Ajax'); // we're not going to use a model for this example, but // it would be easy to use a database thanks to cake var $uses = null; /** * initial page load */ function index() { // preload dynamic data $this->set('data1', 'content will update here'); $this->set('data2', 'here too'); $this->render('neat'); }//index() /** * display content action * * @param int id of content to display */ function view($id) { // content could come from a database, xml, etc. $content = array( array('somebody is baking brownies', 'become a cake baker',), array('knowledge is not enough', 'we must also apply - bruce lee') ); $this->set('data1', $content[$id][0]); $this->set('data2', $content[$id][1]); // use ajax layout $this->render('neat', 'ajax'); }//view() }//ThingsController ?>
<!-- // approot/views/layouts/default.thtml --> <html> <head> <?php print $html->charsetTag('UTF-8'); print $javascript->link('prototype'); print $javascript->link('scriptaculous.js?load=effects'); ?> </head><body> <?php echo $content_for_layout; ?> </body></html>
<!-- // approot/views/things/neat.thtml --> <h1>Really neat stuff here</h1> <?php // update both divs echo $ajax->link('update divs', '/things/view/0', array('update' => array('dynamic1', 'dynamic2')) ); echo ' | '; // use an effect echo $ajax->link('blinders', '/things/view/1', array('update' => array('dynamic1', 'dynamic2'), 'loading' => 'Effect.BlindDown(\'dynamic1\')') ); ?> <hr/> <?php echo $ajax->div('dynamic1'); ?> <h2><span><?php echo $data1; ?></span></h2> <?php echo $ajax->divEnd('dynamic1'); ?> <?php echo $ajax->div('dynamic2'); ?> <h3><span><?php echo $data2; ?></span></h3> <?php echo $ajax->divEnd('dynamic2'); ?>