Tutorial - CakePHP Ajax "Quick Save" with jQuery: CakePHP, jQuery

Tutorial - CakePHP Ajax "Quick Save" with jQuery

Category: PHP & CakePHP Tags: CakePHP, jQuery | Written on Jul 15, 2008

When you are in an administration panel, sometimes you want a "quick save" feature that allows you to save without leaving the page.  Here is how to accomplish this with CakePHP and jQuery.

To start, download jQuery and the jQuery Form Plugin JavaScript.  Include them in your view with the JavaScript helper:

PHP:
  1. $javascript->link(array('jquery', 'form'), false);

Include the RequestHandler in your controller detect an Ajax save attempt.  Also include the JavaScript helper if you haven't already.

PHP:
  1. var $helpers = array('Javascript');
  2. var $components = array('RequestHandler');

Next we want to override our save function with the ajax quick save.  Put this right before your $this->Model->save($this->data) in your save action.

PHP:
  1. if ($this->RequestHandler->isAjax()) {
  2.     if ($this->Article->save($this->data)) {
  3.         echo 'success';
  4.     }
  5.     Configure::write('debug', 0);
  6.     $this->autoRender = false;
  7.     exit();
  8. }

This detects if the request is ajax, then saves the data.  Then it sends back a simple, "success" message to let you know things went fine.  It also writes debug to 0 and doesn't render anything, then exits.

Lastly, lets create and include a JavaScript file that performs the quick save.

JavaScript:
  1. jQuery(function($){
  2.     $('<input type="button" value="Quick Save" />')
  3.         .click(function(){
  4.             $(this).parents("form:first").ajaxSubmit({
  5.                 success: function(responseText, responseCode) {
  6.                     $('#ajax-save-message').hide().html(responseText).fadeIn();
  7.                     setTimeout(function(){
  8.                         $('#ajax-save-message').fadeOut();
  9.                     }, 5000);
  10.                 }
  11.             });
  12.             return false;
  13.         })
  14.         .appendTo('form div.submit');
  15. });

This adds a button called, "Quick Save" to each form on the page where a div with class="submit" exists (you may want to switch this to the id of the form you want to add quick save to). Then It also attaches a click event to the button that submits the form via the jQuery Form Plugin.

In a few simple steps, we've created a quick save feature that saves your data whenever you want without leaving the page.

Comments

#1. Herus Armstrong http://www.egames.com on Jul 17, 2008
Good one :)
#2. Bill http://cakephp.com.br on Sep 02, 2008
Thanks for this tutorial, it's realy usefull.

But, for work, i need to create a div with id ajax-save-message in my page, for print the success message, and i comment the Configure::write('debug', 0); and set autoRender to TRUE.
With this, the message are show.
#3. Fred http://www.fredboucher.com on Oct 06, 2008

Hello,

There seems to be a problem if we use the Security component.
Indeed, the use of this component, the hidden fields (hidden type) are not properly transmitted vision controller, and instead of saving it creates a new record in the table.


With the Security component, the id field of the page (or section) is transmitted like this if we use $ form-> hidden ( 'Page.id'):
data [_Page] [id]
Note the underscore before Page.

To solve the problem temporarily, you must write the hard-hidden field, such as:
<input type="hidden" name="data['Page']['id']" value="the_value" />
#4. Nate http://blog.perfectspac.com on Nov 18, 2008
Additionally, there is a problem using ajaxSubmit in relation to receiving back the response "<h1>Length Required</h1>". It seems there's a 411 error that's returned sometimes. This problem can be fixed by using a GET request instead, but there are times where that doesn't suffice (like when you have a lot of data to submit, the URL gets too long and borks).

So, as much as I'd love to use this method, it seems that until the 411 error code that gets returned is fixed either by CakePHP or by allowing us to send a Content-Length header through the JQuery request, we may be forced to use some other methodology.

Unfortunately, I don't have a solution quite yet, but I've heard that .ajax() can work if you include a blank data{} variable. We'll see.

I hope this helps someone else looking for a solution to this problem.
#5. Edmond on Dec 14, 2008
Hi nice piece of code!
but I have a problem implementing it.
The quick save button doesnt do anything and firebug gives the error
$(this).parents("form:first").ajaxSubmit isn't a function
Any help on this?
#6. Marc Grabanski http://marcgrabanski.com on Dec 14, 2008
Edmond: you probably didn't include the jQuery form plugin.
#7. Dave Miller on Jan 16, 2009
Thanks Marc! Works well for me.

On the off off chance that someone is trying to use this technique with a form containing a text field that contains FCKedit (hey, you never know!) you have to tell FCKEdit to spit out it's current contents before you submit. If your FCKedit text field model.field is, say, Post.message, then your quicksave.js would be:

jQuery(function($){
$('<input type="button" value="Quick Save" />')
.click(function(){
FCKeditorAPI['Instances']['data[Post][message]'].UpdateLinkedField();
$(this).parents("form:first").ajaxSubmit({
success: function(responseText, responseCode) {
$('#ajax-save-message').hide().html(responseText).fadeIn();
setTimeout(function(){
$('#ajax-save-message').fadeOut();
}, 5000);
}
});
return false;
})
.appendTo('form div.submit');
});
#8. Eduardo on Feb 27, 2009
When it does not goes success?

How do I make it go for the failure flow?
#9. Dave http://www.daveashman.com on Mar 31, 2009
Hi ...

So, using the line below:

if ($this->RequestHandler->isAjax()) {
echo "success"
}

I assume that this will only return true if the request is via ajax request. If the user does not have JS enabled, say, you were using this on a public facing contact form etc, then would the normal action take place, and the regular view be displayed ... does that make sense?
#10. Marc Grabanski http://marcgrabanski.com on Mar 31, 2009
Dave, you are correct. If the request is not ajax then it will do the action it would normally, without ajax.
#11. Dave http://www.daveashman.com on Mar 31, 2009
Thanks very much, Marc. I currently learning about Cake via books etc, and have just read about the Ajax helper. The examples did not show any way to process the request if JS was not in use. The author was using:
$this->render('blah', 'ajax');

And I was looking for a way to safe guard against no-js users/version so thanks very much.
#12. Ben http://twitter.com/bkno on May 13, 2009
I found this post useful in getting my ajax support up and running.

Apparently $this->RequestHandler->isAjax() doesn't work in IE7:
https://trac.cakephp.org/ticket/1935

Any recommended alternatives?
#13. Ben http://twitter.com/bkno on May 14, 2009
Following up from my last comment...

I decided to split my action function into two: ajax and non_ajax.
#14. Julien http://blog.juliendesrosiers.com on May 25, 2009
Thanks a LOT for this. Im using jQuery and CakePHP for a CMS. This tutorial saved me hours.

Leave a Comment

Other Reading - Categories