Creating Simple Ajax Pagination with CakePHP 1.3 and Mootools

Creating ajax pagination has gotten more simple and flexible for 1.3. In 1.2 you could only use the built in Ajax pagination if you were using Prototype as your javascript library. With the addition of the JsHelper you can use any Javascript library that an engine has been implemented. My example today will be using mootools. I’ll be basing this, off of a freshly baked index view using the default core templates.

Adding required helper + component

In order to easily do ajax pagination, we’re going to start off by adding:

Show Plain Text
  1.  
  2. var $components = array('RequestHandler');
  3. var $helpers = array('Js' => array('Mootools'));
  4.  

to our controller, this will set us up to use the mootools adapter in the JsHelper and the RequestHandler for automatic disabling of layouts on ajax requests.

Prepare the layout.

In order to use mootools, we’ll need to add it to our layout. Download the latest release of mootools, and save it to app/webroot/js. Inside the <head> element add

Show Plain Text
  1. <?php echo $html->script('mootools'); ?>

Where ‘mootools’ is the name of the file you saved. Also ensure that you have a single element wrapping $content_for_layout. Mine looks like

Show Plain Text
  1. <div id="content">
  2.     <?php echo $content_for_layout; ?>
  3. </div>

A single wrapping div with an id will make updating it later that much easier. The helpers automate replacing a single element, if you have different layout requirements, then your code will be a bit different.

Setting up the paginator helper

Next we need to let the PaginatorHelper know that we will want to create ajax links using the options().

Show Plain Text
  1. <?php $paginator->options(array(
  2.     'update' => '#content',
  3.     'evalScripts' => true
  4. ));
  5. ?>

The evalScripts option is passed into the Request.Html options in Javascript and lets Mootools know that it should eval() any script tags it finds in the response html. At the bottom of our index.ctp, after all the paging links add:

Show Plain Text
  1. <?php echo $js->writeBuffer(); ?>

This tell the JsHelper to write all of its buffered script elements into a script tag. When the buffer is output it is also cleared, so you don’t have to worry about outputting the same Javascript twice. You output the buffer at the bottom of the view, because when the new content is inserted into the DOM it will not have any events bound. By including the events code in the response and using evalScripts the events are rebound, allowing chained Ajax requests.

If you refresh the page you should now have functioning Ajax pagination. However, we can add a bit more spice with some additional effects. By adding a few more options, we can enable a simple fade in / fade out.

Show Plain Text
  1. <?php
  2. $paginator->options(array(
  3.     'update' => '#content',
  4.     'evalScripts' => true,
  5.     'before' => $js->get('#content')->effect('fadeOut', array('buffer' => false)),
  6.     'success' => $js->get('#content')->effect('fadeIn', array('buffer' => false))
  7. ));
  8. ?>

The above will generate the required Javascript code to fade in and fade out the #content div before and after the content is updated. And although the helper doesn’t generate the most elegant, efficient or beautiful javascript, it gets the job done and fast. So that’s it, you can easily replace the ‘before’ and ‘after’ options with more sexy effects if you want.

Comments

Awesome! The more I see examples with the JsHelper, the more I get excited about it. I’m Really looking forward to the release of 1.3. Keep up the great work!

Nick on 27/10/09

I do have a question, if I were using Prototype as my JS Library would my update option change from ‘#content’ -> ‘content’ (notice the lack of #). Or does the JsHelper use $$() instead of $() for Prototype element grabbing?

Nick on 27/10/09

Nick: With prototype you would still use ‘#content’. The prototype adapter will use $() or $$() based on the selector you provide. The same is true of the Mootools adapter.

mark story on 27/10/09

In order to use mootools, we’ll need to add it to our layout. Download the latest release of mootools, and save it to app/webroot/js

Are we supplosed to save this file as mootools.js and do you recommend the YUI Compressed version of Mootools like it is recommended on the Mootools site?

Jon on 31/10/09

Jon: I use the compressed mootools, in production situations. While developing I much prefer the uncompressed source. It makes debugging with Firebug/webinspector far less painful.

mark story on 31/10/09

mark story: What are you using for compressing js files? Nice, simple solution is showen here http://www.milesj.me/blog/read/32/CSSJSAsset-Compression-In-CakePHP What I miss is merge js files into one file.

Is there any way to merge js file in javascript helper? So when I use $javascript->link(array(‘jquery’,‘default’)); the output js file would look like jquery_default.js

Luboš on 14/11/09

Mark, great post and great work. I’ve used your example with jQuery but the events don’t seem to chain correctly. The first ajax request is successful however as it does not seem to bind the events in the ajax reply, it results in a non-ajax request on second event.

evalScripts does not seem to have any affect with jQuery – is this a known limitation or have I missed something?

Ryan on 14/12/09

Thanks – this helped me.

Can I produce two simultaneous effects? For example, can I fade out my content div and show my progress/spinner div, then hide my progress/spinner div and fade in my content div?

Jeremy Burns on 24/3/10

can u show the demo ??

- thanks =

konk on 21/4/10

ohhh, thats the demo right:)…..!

thanks

konk on 21/4/10

Hi, updating a div ‘#tablesajax’ containing only tables and navigation does refresh the whole index.ctp page in this same div? Yet it is still a XHR request as followed through firebug.
Eventhough I have followed this tutorial strictly… any idea why?

Mike on 25/4/10

What about gif loading image?

Manuel on 29/4/10

Manuel: Well in the before/after callbacks you can apply effects to a loading image instead of the content region.

'before' => $this->Js->get('#loading')->effect('fadeIn', array('buffer' => false)),
'after' => $this->Js->get('#loading')->effect('fadeOut', array('buffer' => false))

Should do the trick I would think.

mark story on 1/5/10

Thanks for the answer, but I mean how to add effects to two or more elements when Ajax request is succesfull. On CakePHP 1.2 I can do stuff like this:

‘complete’=>“Element.hide(‘myImg’);Effect.Appear(‘myDiv1’);Effect.SlideDown(‘myDiv2’)”)

but how can I do this with JsHelper on 1.3?

manuel on 1/5/10

Manuel: Well you could either append multiple calls to JsHelper, or you could just use some literal javascript strings like you did before. Both will work.

mark story on 2/5/10

How make a observerField with mootools in cakePhp 1.3?

Celso Fontes on 3/5/10

I am doing a a observerField in this way:

  1. Select
    echo $this->Form->input(‘Vclassroom.type’,array(‘options’=>$types, ‘between’=>’: ‘));

#observerField
$this->Js->get(’#VclassroomType’)->event(‘change’, $this->Js->request(’/admin/vclassrooms/type/’, array(‘update’ =>’#fooDiv’, ‘dataExpression’ => True, ‘before’ => $this->Js->get(’#loading’)->effect(‘fadeIn’, array(‘buffer’ => false)), ‘data’ => $this->Js->serializeForm(array(‘isForm’ => False, ‘inline’ => True)))));

Manuel Montoya on 13/5/10

Hey,

i’ve tryed to get this ajax pagination work but not very successfully. Instead of Mootools i use Jquery as default. I baked a brandnew cake application with just one table (posts).

unfortunately i get some prototype links like Event.observe(‘link552139870’, ‘click’, function(event) […]

I even tryed to set jquery as JS Enginge but without success. var $helpers = array(‘Js’ => array(‘Jquery’));

I use the lates stable 1.3.

Does anyone has an idea?

Christian on 21/5/10

Excellent! And it actually works!

Cheers!
Maciej

Pysiak on 1/8/10

I have followed perfectly your guide but it only works at 50%.

I just have two link for pagination: 1 & 2. If I reach page through: http://my_web.com/items/admin/page:1 link to page 2 is active, if I click this link the second page will be opened in ajax style. OK! Now, link for page 2 is disabled and link for page 1 is active, but, if I click this link the page will be reloaded entirely as normal call.

Viceversa happen if I call http://my_web.com/items/admin/page:2. Clicking on page 1 will happen in AJAX, successivly clicking on page 2 will happen with classic call.

Why?

Mariano on 12/8/10

< prev12

Have your say:

*
* You can use Textile markup, but be reasonable