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.

9 Responses to “AJAX in CakePHP with jQuery”

  1. paul on April 9th, 2009 at 6:30 am

    Thanks man! Finally the result of a long search, now i’m lucky :)

    Report this comment

  2. Dhana on April 9th, 2009 at 9:30 pm

    Glad you found it helpful :)

    Report this comment

  3. Jimmy on April 18th, 2009 at 4:05 pm

    Most helpful post I’ve found on this subject. Thanks very much!

    Report this comment

  4. ZedR on May 6th, 2009 at 8:27 am

    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

  5. Dhana on May 6th, 2009 at 12:44 pm

    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

  6. ZedR on May 6th, 2009 at 9:40 pm

    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

  7. Dhana on May 7th, 2009 at 12:54 pm

    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

  8. ZedR on May 8th, 2009 at 7:24 am

    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

  9. Chris on January 19th, 2011 at 11:45 am

    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

Leave a Reply




You may use the tags listed below in your comments:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Published in
Tagged under
Some other categories