AJAX in CakePHP with jQuery
I’ve been tinkering around with CakePHP for the last few weeks out of curiosity. The process has been fun and has made me enjoy PHP much more especially since I am building my own “todo” application from the ground up as a learning tool. After getting the application to work the usual way (not spiced up with some AJAX goodness), I decided to add in some AJAX support. Although CakePHP comes with AJAX helpers that will certainly help make development a snap, I wanted use jQuery.
Here’s a snippet of my code that I used to add a task. The form below is used to add a task.
1 2 3 4 5 6 | < ?php
e($form->create('Task', array('controller' => 'task', 'action' => 'add', 'class' => 'form')));
e($form->input('title', array('label' => 'Title:', 'class' => 'long focus')));
e($form->submit('buttons/add.png', array('alt' => 'Add', 'class' => 'add')));
e($form->end());
?> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | $('.add').click(function(){
var parent = $(this).parents('form');
var task = $('.long', parent).attr('value');
if(task == ''){
$(parent).before('<div class="issue">You need to enter a title for the task.</div>');
}
else{
var formData = $(this).parents('form').serialize();
$.ajax({
type: 'POST',
url: '/tasks/add',
data: formData,
dataType: 'json',
success: function(data){
var row = '<tr id="row_'+ data.Task.id +'">';
row += '<td><a href="/tasks/show/' + data.Task.id + '">' + data.Task.title + '</a></td>';
row += '<td>' + data.Task.created + '</td>';
row += '<td>' + data.Task.completed + '</td>';
row += '<td><form method="POST" action="/tasks/delete/' + data.Task.id + '"><input class="delete"
type="image" src="img/icons/cancel.png" title="Delete this task" alt="Delete" /></form></td>';
row += '</tr>';
$('.display tbody').append(row);
$('#row_' + data.Task.id).animate({ 'backgroundColor': '#F2FFBF'}, 300, function(){
tableFunctions.stripe();
})
},
error: function(message){
alert(message);
}
});
}
return false;
}); |
This is where the magic happens. Notice the class attribute in the form above called “add”. The Javascript function checks if something with the class “add” has been clicked. When it is, the form data is serialized using jQuery’s serialize function. Then, the data is submitted to the controllers add function. The data type we want returned in this case is json since we would want the details of the task added so that we could add it to the tasks table.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | function add() {
if(!empty($this->data) && $this->Auth->user('id')) {
$this->data['Task']['user_id'] = $this->Auth->user('id');
$this->Task->create();
if($this->Task->save($this->data)) {
$id = $this->Task->getInsertID();
$this->Task->recursive = -1;
if($this->RequestHandler->isAjax()) {
$this->autoRender = false;
$task = $this->Task->findById($id);
$task['Task']['created'] = $time->format($format = 'd M Y', $task['Task']['created']);
$task['Task']['modified'] = $time->format($format = 'd M Y', $task['Task']['modified']);
return(json_encode($task));
}
else {
$this->Session->setFlash('Your task has been added', 'default', array('class'=>'information'));
$this->redirect(array('action' => 'show', $id));
}
}
else {
$this->Session->setFlash('There was an issue adding your task. Try it again.', 'default', array('class' => 'issue'));
}
}
} |
In the add function of the controller, RequestHandler->isAjax() is used to identify if it’s an AJAX call. If it is, the usual things are done, but what is returned is the new task details converted to a json using PHP’s json_encode function. Also, there is no need to render the view here, so autoRender is set to false.
The success function receives the json output and forms the new row. To indicate a new row was added so that the user knows something happened, the background color of the new row is animated for a short duration. The stripe function you see in the callback is just another function I have to stripe the alternate rows. And that’s about is.
Although this does seem a lot longer or more complicated than using the AJAX helpers, sometimes it’s good to know how things actually work. Another good reason of writing your own AJAX functions could also be boiled down to performance. The issue I have with AJAX helpers at times is it tends to return a whole lot of information when you just need it to return a small chunk of information.
Note: The code above will work even when Javascript is disabled.

Thanks man! Finally the result of a long search, now i’m lucky
Report this comment
Glad you found it helpful
Report this comment
Most helpful post I’ve found on this subject. Thanks very much!
Report this comment
Nice!!
I am trying to do the same thing but I m getting [object XMLHttpRequest] in the error message. What must be the problem? I checked the formData. It starts with _method=POST&data…. What is rowData?
Report this comment
ZedR,
Do you have a test page that I could see? rowData is the result returned by the server, which in this case is the json string of the newly added row.
Report this comment
Dhana,
My jquery code:
$(‘.add’).click(function () {
var formData = $(this).parents(‘form’).serialize();
$.ajax({
type: ‘POST’,
url: ‘/blog/users/register’,
data: formData,
dataType: ‘json’,
success: function(rowData){
var reg_html = ‘Thank you. Please check email for the confirmation link. Click on it to activate account.’;
reg_html += ‘Resend email? Click here:’;
reg_html += ”;
$(‘#registeration’).html(reg_html);
},
error: function(message){
alert(message);
}
});
// }
return false;
});
form view:
create(‘User’,array(‘action’=>’register’,'id’=>’register’, ‘class’=>’form’)));?>
Register user
input(‘firstname’, array(‘label’=>’First name’, ‘id’=>’firstname’)));?>
input(‘lastname’, array(‘label’=>’Last name’, ‘id’=>’lastname’)));?>
input(‘email’, array(‘label’=>’Email’, ‘id’=>’email’)));?>
input(‘password’, array(‘label’=>’Password’, ‘id’=>’password’,'type’=>’password’)));?>
input(‘confirm_password’, array(‘label’=>’Confirm Password’, ‘id’=>’confirm_password’, ‘type’=>’password’)));?>
input(‘sec_que’, array(‘label’=>’Security question’, ‘id’=>’sec_que’)));?>
input(‘sec_ans’, array(‘label’=>’Security answer’, ‘id’=>’sec_ans’)));?>
submit(‘Submit’,array(‘class’=>’add’)));?>
end());?>
register action in User controller:
if(!empty($this->data)) {
//unset($this->data['User']['confirm_password']);
$this->data['User']['password'] = $this->Auth->password($this->data['User']['password']);
$this->data['User']['confirm_password'] = $this->Auth->password($this->data['User']['confirm_password']);
$this->User->create();
$this->data = Sanitize::clean($this->data);
if($this->User->save($this->data,false)) {
$this->sendConfirmationEmail($this->data['User']['email'],$this->data['User']['firstname'], $this->data['User']['password']);
//$userdata = $this->data;
$id = $this->User->getInsertID();
$this->User->recursive = -1;
if($this->RequestHandler->isAjax()) {
$this->autoRender = false;
$user=$this->User->findById($id);
return(json_encode($user));
}
else {
$this->Session->setFlash(‘Your account has been created’, ‘default’);
}
}
The ajax operation always returns error. I tried data.User.email in the jquery code too instead of rowData.User.email.
Thanks a lot.
Report this comment
ZedR,
Your JS code looks all right. Did you check to make sure the user was created and added to the db? I guess you could echo the value onto the page first to see if the user is indeed being retrieved after being saved. Also try the Firebug tool to see if the error is happening during the submission process.
Report this comment
Thanks for the reply Dhana.
I have checked my code. It does add record to the db. I even tried something else to return as return value, but still no success.
Report this comment
Hey ZedR,
I had the same issue and solved it:
add the following line before
$this->autoRender = false:Configure::write ( 'debug', 0 );I’m using CakePHP 1.3.6
Hope it helps (btw, great article!)
Report this comment