Combining Modalbox & CakePHP

I’m pretty sure this can be implemented more elegantly, but I’ll describe my attempt to unite Modalbox with CakePHP 1.2.

First example – a modal box view
This example shows the steps I’ve taken to flavour a freshly baked cake app with modalbox. The starting point is a customer model, a controller and some basic index, view and edit views.
Showing a cakephp view in a modalbox, is just a few snippets away. Just make sure you include prototype, scriptaculous and the modalbox javascript and the modalbox css file in the default layout…

1
2
3
4
5
/app/views/layouts/default.ctp:
echo $html->css('modalbox');
echo $javascript->link('prototype');
echo $javascript->link('scriptaculous.js?load=effects');
echo $javascript->link('modalbox');

Then create the appropiate link to the view you want to load inside the modalbox. For example, if you want to show customer details from the customers/index.ctp view:

1
2
# ...somewhere in the loop that lists customers:
echo $html->link('View', array('action' => 'view', $customer['Customer']['id']), array('title' => 'Customer details', 'onclick' => "Modalbox.show(this.href, {title: this.title, width: 400}); return false;"));

Make sure you use the RequestHandler component so that the customer view is displayed in the ajax.ctp instead of the default.ctp layout. You can do this by making sure the following line is in /app/app_controller.php:

1
var $components = array('RequestHandler');

And… there you go! When you click the view link, the modalbox slides in, while the rest of the page dims to gray. When you hit the escape button, click the little ‘X’ or click anywhere in the gray area, the modal box slides back where it came from.

Ok, now forms!

This is where the example pages don’t seem to apply anymore. Or… this is where my concept of AJAX, CakePHP, Modalbox, etc. is fundamentally wrong… you tell me!

By calling an ‘edit’ view instead of the ‘view’ view, you’ve got yourselves a form inside the modalbox! Also very nice!
After submitting the edit form, you’ll get redirected to the index page again. That’s when the form validates.
Wait until you omit a required field. Instead of the index page, you get redirected to the edit form itself rendered in the ajax layout. There’s no single line of code yet that makes sure that the form will end up in the same modalbox.

To solve this, you need to replace the $form->create call in the edit view by $ajax->form. The form, starting with the tag generated by the Ajax helper, will submit using XMLHttpRequest instead of a normal HTTP request. In this way, the modalbox stays open and will be filled with whatever the form returns!

This was the form-helper call:

1
echo $form->create('Customer');

…and the ajax-helper equivalent:

1
2
3
4
5
echo $ajax->form('edit', 'post', array(
'model' => 'Customer',
'url' => array( 'controller' => 'customers', 'action' => 'edit'),
'update' => 'MB_content'
));

In order to make the Ajax helper available in the view, make sure you have included it in the controller:

1
var $helpers = array('Html','Javascript', 'Ajax');

I’m still wondering why the calls aren’t a little bit more alike…

This brings us one step closer…. or one step too far??
All content will be rendered inside the modalbox. We need to tell modalbox when it’s not needed anymore. For example, when the form validated.

This can be done with a small javascript function that we define in the Default.ctp layout:

1
2
3
4
5
6
7
8
9
10
11
12
13
function closeModalbox()
{
if ($('closeModalbox')) {
// hide the modal box
Modalbox.hide();
// refresh the current page
location.reload(true);
} else {
// resize to content (in case of validation error messages)
Modalbox.resizeToContent()
}
return true;
}

The function checks if there’s a div element with id=”closeModalbox”. If that is the case, it will close the modalbox and refresh the current page. Which, in itself is not so Ajax….(but it works great!)
If it can’t find the div element, it will resize the modalbox to it’s fresh content. To make sure the function is called, we can hook it into the Ajax form by adding the following line to the options array:

1
'complete' => 'closeModalbox()'

In the edit view, we need to make sure that the closeModalbox-div is echoed conditionally:

1
if (isset($closeModalbox) && $closeModalbox) echo "<div id='closeModalbox'></div>";

The $closeModalbox variable is, in his turn set from the controller after the data is successfully saved.

Last, but not least…. it’s relatively simple to be able to fall back to a non-ajax form.

Code
And since you probably allready lost the overview, here’s the complete source code

i hope this can be implemented if yo want any form on pop-up box..