Edit in place with JQuery and CakePHP
Sometimes it is quite handy if the users of an application can simply click on some text to edit it. Adding such a feature to your application is not very difficult as you will see.
At first we have to get the Jeditable plugin (plus the JQuery library if you don’t have it already) and place it in app/webroot/js. In this folder we also create a js file which will contain the Javascript code we have to write (I will name this file example.js).
To use the Javascript files, we have to include them in the layout (or in the view, see “Referencing Javascript files” for more information):
// app/views/layouts/default.ctp
<?php echo $javascript->link(array('jquery-1.2.3', 'jquery.jeditable', 'example')); ?>
Don’t forget to add the Javascript helper to the $helpers array of your (App)Controller.
The next step is to write the “normal” functionality of the application, in this example we simply list the titles of all posts. The controller (app/controllers/posts_controller.php):
class PostsController extends AppController {
public function index() {
$this->set('posts', $this->Post->find('all'));
}
}
And the view (app/views/posts/index.ctp):
<?php foreach ($posts as $post): ?>
<div class="post" id="<?php echo $post['Post']['id']; ?>”><?php echo $post['Post']['title']; ?></div>
<?php endforeach; ?>
With that we are ready to add the edit in place functionality. Thanks to the Jeditable plugin this is an easy task: we only have to define the editable element(s), the url to which the changes should be posted, plus some parameters.
// app/webroot/js/example.js
$(function() {
$('.post').editable('/posts/updateTitle', {
id : 'data[Post][id]‘,
name : ‘data[Post][title]‘,
type : ‘text’,
cancel : ‘Cancel’,
submit : ‘Save’,
tooltip : ‘Click to edit the title’
});
});
I think this code is self-explanatory (if not, please leave a comment), so we can go on to implement the updateTitle action. We also add the RequestHandler component to our controller, so that the response of the updateTitle action automatically uses the ajax layout:
class PostsController extends AppController {
public $components = array('RequestHandler');
public function index() {
$this->set('posts', $this->Post->find('all'));
}
public function updateTitle() {
if ($this->data) {
App::import('Core', 'sanitize');
$title = Sanitize::clean($this->data['Post']['title']);
$this->Post->id = $this->data['Post']['id'];
$this->Post->saveField(’title’, $title);
$this->set(’posttitle’, $title);
}
}
}
Last, but not least, we have to create a simple view for the updateTitle action (app/views/posts/update_title.ctp):
<?php echo $posttitle;?>
That’s it, our application now provides edit in place functionality. Happy baking :)




Thanks, but how about security?
I mean, what if somebody will call updateTitle from it’s own code with some bad data?
Oh! Thanks!
Well that is very slick. Yet another reason to switch to jQuery as the default scripting library. ;-)
Two questions though:
(1) Why the call to read()? That seems like an unnecessary database hit just to set the ID. I can’t see any case under which the existing record data would be used, but maybe I am missing something.
(2) (And I know nothing about JEditable beyond what you’ve shown here, but…) is there some out-of-band way (i.e. a dialog box) to handle validation or database errors? How would that be handled in this context?
@all: Thanks for your comments!
@Taewoo: You got me, I forgot to sanitize the input :| I fixed it in the article. Thanks! And depending on the application additional security measures like a security token may be necessary.
@nate: You are right, the read() statement is not necessary, I removed it. Thanks!
I think you would use the “callback” parameter to specify a function for handling such a situation.
@nate: Though i haven’t studied jQuery much i think you should also consider Mootools as alternative for default js library. I respect jQuery alot. So…just to be clear… i’m not trying to provoke ‘Which is the best js framework’ discussion… just to mention another great framework which deserves attention before making the decision
@cakebaker: Great example :)
@purepear: I think the idea is to move to the best framework for CakePHP’s needs. It doesn’t make sense to maintain multiple sets of the same code to support multiple libraries.
Great! I did the same thing with an app of mine.
I hacked a bit in jEditable to support multiselects. :)
Workes liek a charm.
Good that you wrote it down. Reminded me to do this more often is I solved some issues I have during programming.
Instead of using a file for the function (in your case exemple.js), you could put in the view from being loaded on every page. One way to do this is by placing the following code before the html of view (or any part thereof):
<?php $functionForExemple = <<<EOC $(function() { $('.post').editable('/posts/updateTitle', { id : 'data[Post][id]‘, name : ‘data[Post][title]‘, type : ‘text’, cancel : ‘Cancel’, submit : ‘Save’, tooltip : ‘Click to edit the title’ }); }); EOC; $javascript->codeBlock($functionForExemple, array(’inline’=>false)); ?>That’s it. ;)
Hei,
Your blog has “eat” part of my code. :)
Daniel: you can ajust?
Thanks.
The irony for me is that I was looking at implementing this yesterday, at the exact same time this article was being written. And I came up with (just about) the exact same code. Well, the ‘just about’ part was enough to prove your version is better.
With the addition of a toggle link to turn the editors on and off, a wrapper around Cake’s __() method to put the output within a span, and a callback for the editors to update all similar spans upon success, I’ve been able to build an interface for users to add translations in-place with great ease. Bakery article coming soon. And of course you’ll get most of the credit.
[...] Edit in place with JQuery and CakePHP - cakebaker (tags: cakephp jquery editinplace) [...]
@purepear: Thanks :)
@Charlie: Yes, I can only recommend to write down stuff you have done.
@Juan: Your comment is fixed now.
Yes, that’s a possible solution. But I would use it only for small scripts as you won’t have any syntax highlighting/code completion/syntax checking in your IDE if you treat the Javascript code as PHP string.
@Tommy: I’m looking forward to your article :)
i am newbie in cakephp…
i have a problem.
……………………………………………..
id | name | email
……………………………………………
1 | radar | a@a.com
…………………………………………..
how if i want to edit more then one, I want edit name and email..
sorry i can not speak english….
thanks
@radar: You could use two classes “name” and “email”. And then in your Javascript you could use the editable plugin with two different urls.
Hope that helps!
What about authorization?
@tozwierz: If you have to be authorized to use this functionality, you would have to check for example in a beforeFilter whether the user is logged in and then in updateTitle() you have to check if the current user can update the title of the specified post.
Hope that answers your question.
@cakebaker: Thx for the answer.
Well, I asked the wrong question :-) It should rather: How to combine your example with Cake builtin Auth Component?
My expirience is that Auth Component will redirect unauthorized request to a login form.
@tozwierz: I don’t have used the Auth component together with Ajax yet, but there is a property $ajaxLogin which may be what you are looking for: “The name of an optional view element to render when an Ajax request is made with an invalid or expired session”.
Hope that helps.
@cakebaker: You save my day! I’ll look into it. Thx!
@tozwierz: You are welcome!
[...] http://cakebaker.42dh.com/2008/02/24/edit-in-place-with-jquery-and-cakephp/ [...]
Thanks for the tutorial. Works great in Leopard and perfectly in Firefox on a PC. However, this solution will not work in IE7. Has anyone else experienced this?
@Chris: Hm, you may ask in the JQuery mailing list, maybe someone there experienced the same issue…