Creating Ajax form in Cakephp (with Prototype.js)

(If you are using jQuery with cakephp you may want to view this article, Creating Ajax form in Cakephp using jQuery )

With the help of prototype/JavaScript we can build really cool and fully functional ajax form in CakePHP really fast.

I have been using the ajax forms in CakePHP for a long time now but in the view of continuous development work always on at CakePHP framework development community i have had to alter ways to write the same code. So here is the latest one.

Prior to Cakephp 1.2 i had been using

<?php echo $ajax->form(
'search_retailers','POST', 
array('update' => 'retailersListID',
'loading'=>"Element.show('plsLoaderID')",
'loaded'=>"Element.hide('plsLoaderID')",
'before'=>""))?>

to create a ajax form request element but when i tried to update my old site to latest 1.3 version of cakephp it would not work anymore. The latest way to create a ajax form element had turned to something like this:

<?php
echo $ajax->form(array('type' => 'post',
'options' => array(
'model'=>'Charity',
'update'=>'retailersListID',
'url' => array(
'controller' => 'Charity',
'action' => 'search_retailers'
),
'loading'=>"Element.show('plsLoaderID')",
'loaded'=>"Element.hide('plsLoaderID')"
)
));
?>

So i had to replace my /cake/ directory to update to the latest version but again i had to do changes (very few and fast though) to make my old ajax forms working with latest version. At the last i came up with this post which shows how to create ajax form in the latest version 1.3.

In this example we will learn to search a database table using ajax form and then display results right under the form itself. We will display “results found” or “results not found” titles in the result area after the request is complete. To customize results, you will need tp edit controller action or corresponding view code yourself.

A loader, while the ajax request is in process will be shown and eventually hidden when the request is complete and results are ready to display.

Let’s start building it. We assume that we have an existing action “index” in our CharityController and it has a corresponding view “index.ctp” within which we place our ajax form. This form will be submitted to a different action “search_retailers” of the same Charitycontroller and results will be shown just under the ajax form in the “index.ctp” view through ajax.

Okay. The following line of code will generate a <form> tag with a few attributes and a corresponding javascript code right under the form tag. Following the complete php code which we place in our index.ctp view (you will need to call prototype.js library inside your layout or header view file to make ajax work):

<?php
echo $ajax->form(array('type' => 'post',
'options' => array(
'model'=>'Charity',
'update'=>'retailersListID',
'url' => array(
'controller' => 'Charity',
'action' => 'search_retailers'
),
'loading'=>"Element.show('plsLoaderID')",
'loaded'=>"Element.hide('plsLoaderID')"
)
));

echo '<div>
<p>
Enter Keyword:<br>';
echo $form->input("AffiliateStore.keyword",array('label'=>false,'div'=>false,'class'=>'textlarge'));
echo '</p>
<p>';
echo $form->submit("  List Retailers  ",array('label'=>false,'div'=>false,'class'=>'button')); ?>
echo '</p>
<div id="plsLoaderID" style="display:none;">';
echo $html->image("ajax-loader-orange.gif");
echo '</div>
<div id="retailersListID"></div>
</div>';

echo $form->end(); ?>

The php code above generates somewhat similar html + javascript code as under when loaded into the browser. I say similar because it will generate random form id each time you load the page (form2064479612 here). Here is the html output:

<form id="form2064479612" onsubmit="event.returnValue = false; return false;" 
method="post" action="/newcake/Charity/search_retailers">
<fieldset style="display: none;"><input name="_method" value="POST" 
type="hidden"></fieldset>
<script type="text/javascript">
//<![CDATA[
Event.observe('form2064479612', 'submit', function(event) { 
new Ajax.Updater('retailersListID','/newcake/Charity/search_retailers', {
asynchronous:true, evalScripts:true, onLoading:function(request) {
Element.show('plsLoaderID')}, onLoaded:function(request) {
Element.hide('plsLoaderID')}, parameters:Form.serialize('form2064479612'), requestHeaders:['X-Update', 'retailersListID']}) }, false);
//]]>
</script>
<div>
<p>
Enter Keyword:<br>
<input name="data[AffiliateStore][keyword]" class="textlarge" value="" id="AffiliateStoreKeyword" type="text">            </p>

<p>
<input label="" class="button" value="  List Retailers  " type="submit">
</p>
<div id="plsLoaderID" style="display: none;"><img src="/newcake/img/ajax-loader-orange.gif" alt=""></div>
<div id="retailersListID"></div>
</div>

Although the code above is quite self explainatory i will explain the main function $ajax->form() used in the view in detail.

The $ajax->form() defined in /cake/libs/view/helpers/ajax.php can accept all option within a single argument in array format. The first element ‘type’ of the passed array defines ‘method’ of the form and if omitted it takes POST by default. You can define all additional and needed options within second ‘options’ element. Breaking ‘options’ array elements further, it accepts “model” which is the name of the model, not important though. The ‘update’ element is the id of HTML element, normally a DIV element which will be populated with results returned by the ajax request. The ‘url’ can carry form action url as a string or in the form of an array which again has the controller and action name within itself. In this example, we will pass an array as url which has controller and action names as “Charity” and “search_retailers” respectively. Next element of the ‘options’ array is the ‘loading’ which can carry JavaScript code to be run while the request is in process. In the example, we will show a spinning animated image wrapped within “plsLoaderID” DIV element with the help of Element.show() method of prototype library. The last element of ‘options’ array here is ‘loaded’ element which also contain a piece of JavaScript to be run just after the request has finished loading the data in buffers. In this example, we will hide that spinning animated image container “plsLoaderID” with Element.hide() method of prototype when the request has finished loading the data. That’s all explaining the parameters of $ajax->form() method.

Now we create a “search_retailer” function in our CharityController which processes the request submitted through our form. Here is the example of this function:

function search_retailer()  {

$keyword = $this->data['AffiliateStore']['keyword']; //storing keyword submitted into a variable

//load model AffiliateStore is not loaded here

$stores = $this->AffiliateStore->find('all', array('conditions'=>array('`store_name` like'=>'%'.$keyword.'%')));

$this->set('stores', $stores); //setting variable to be used in our view

}

Now, as the stores data is stored in $stores variable we will create a new view named “search_retailer.ctp” inside views/charity/ directory to display the data. The final html output by our “search_retailer.ctp” view will be shown within our ‘update’ id which is “retailersListID” here in this example. Below is the example code written inside search_retailer.ctp view:

<?php
if(!empty(stores))  {
echo '<p>Results found</p>';
foreach($stores as $store)  {
echo '<li>'.$store['AffiliateStore-']['store_name'].'</li>';// you can customize it furter
}
} else  {
echo '<p>Results not found</p>';
echo '<p>Sorry! no such stores were found!</p>';
}
?>

Once all things are in place and “List Retailers” button is pushed you should see a printed list of record or just a message “Sorry! no such store was found!” with a “Results not found” title.

I hope this example gives you enough idea about how to create an ajax form with the help of prototype within cakephp. Your comments are appreciated.

2 thoughts on “Creating Ajax form in Cakephp (with Prototype.js)

Leave a Reply