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…
On the example.js why does it use both ` and ‘ I get an illegal character
on line 3
id : `data[Post][id]`,
Any idea why?
@Josh: Unfortunately, Wordpress makes quite a mess with quotes :| So please replace the wrong characters with the correct characters.
Is there a way to apply this to a checkbox or a selec box meaby ?
@eiksihi: For a label of a checkbox it is done in the same way as shown in the article. For a select box it is probably done in the same way, even though I never used it with a select box yet.
Hope that helps!
Hi Daniel, nice article!
Any chance of slapping an example “editable in place” item at the end of the article? Or a demo page?
Would be much appreciated!
@MicroAngelo: Thanks!
You can find a demo page on the author’s website. Or are you looking for something different?
is it possible for a single $(‘.post’).editable() call to handle multiple fields with different names?
eg.
in the view:
<div class=”post” id=”">
<div class=”post” id=”">
in the .js:
$(‘.post’).editable(‘/posts/updateTitle’, {
name : ‘data[Post][title + subject]‘, <– or some jQuery that can identify the field it’s editing
….
});
@alex: Well, the easiest way is to give your elements an id ;-)
ya, the comment editor nuked some syntax in the div, but the key part of the question is with the js. assuming each element has a unique id, is there a variable i can use in the name parameter that will be set to the current element being edited?
eg. $(‘.post’).editable(‘/posts/updateValue’, {
name : ‘data[Post]['+{variable}+']‘,
}
@alex: Hm, somehow I don’t see what you try to accomplish. If you use the following snippet:
$('.post').editable('/posts/updateValue', { id : 'data[Post][id]', name : 'data[Post][title]' }then you can access the id of the edited element in your CakePHP action with:
And hence it doesn’t make much sense to me to use the id as key for the value…
the problem with using your snippet is that it applies for a single field (title). i want to apply the editable feature for each and every field on the page.
in doing this, i am trying to determine whether it’s possible to have a single .editable() call that handles all fields, or whether i need to have an .editable() for each field.
@alex: Ah, now I understand what you try to do ;-)
Well, you can use a single .editable() call. You just have to make sure to select all relevant fields and that the IDs of the elements are unique, e.g. by prefixing them with the model name like “post_1″. On the server side you can then analyze the IDs and use the corresponding models to save the changes.
great, can you provide a code snippet for this? (i’m still relatively new to jQuery)
let’s say i wanted to have a single .editable() for 3 fields: title, subject, and author, all of which are simple text fields. what would the js, view and controller code look like?
@alex: Well, the js code is almost the same as above, you just have to change the names.
In the view the fields have to use the same class, e.g. “editable”, and the IDs have to be something like “title_1″, “subject_1″, “author_1″.
And the controller code is also almost the same as above, you just have to check the ID and then save the value to the corresponding field.
I think that should be enough for you to write the corresponding code ;-)
that worked, thanks! for those interested, here’s my code:
view:
javascript:
$(function() { $('.edit').editable('/posts/updateValue', { id : 'data[Post][id]', name : 'data[Post][value]' }); });controller:
public function updateValue() { if ($this->data) { uses('sanitize'); $mrClean = new Sanitize(); $value = $mrClean->clean($this->data['Post']['value']); // splits field from id list($field, $id) = split('_', $this->data['Post']['id']); $this->Post->id = $id; $this->Post->saveField($field, $value); $this->set('postValue', $value); } }grr, how do you add a code snippet in these comments? (pre didn’t work) can you please delete the post above so i can re-post it correctly.
@alex: Cool to hear it worked :)
Ok, I added “pre” tags to your previous comment plus the missing code for the view code. Adding code is always a bit of a pain, as you have to escape all tags, or else they disappear :| Do you know by accident a wordpress plugin that preserves code snippets? ;-)
thanks for adding “pre” tage, but the view code is still incorrect. it should be the following (replace {} with ):
{div class=”edit” id=”title_{?php echo $post['Post']['id']; ?}”}{?php echo $post['Post']['title']; ?}{/div}
{div class=”edit” id=”subject_{?php echo $post['Post']['id']; ?}”}{?php echo $post['Post']['subject']; ?}{/div}
{div class=”edit” id=”author_{?php echo $post['Post']['id']; ?}”}{?php echo $post['Post']['author']; ?}{/div}
as for a wordpress plugin that preserves code, a quick google search reveals: http://www.thunderguy.com/semicolon/wordpress/code-markup-wordpress-plugin/
@alex: Ok, it is now fixed.
Thanks for the link, I tested that plugin, but it was a bit buggy. In the meantime I found another plugin (http://www.jimimorrisonshead.com/2007/03/11/wordpress-plugin-code-autoescape/) that seems to work fine and which is now enabled here. So it is no longer necessary to escape code snippets ;)
I’ve implemented your code and all works well except I get an error once the post has been made.
Everything is updated to the database and once I refresh the page the changes are indeed made but I still get the cakePHP error when I save the form field.
Undefined variable: title [APP/views/projects/update_title.ctp, line 1]
Line 1 (and all) of update_title.ctp:
updateTitle action of the controller:
function updateTitle() {
if ($this->data) {
App::import(‘Core’, ’sanitize’);
$title = Sanitize::clean($this->data['Upload']['title']);
$this->Upload->id = $this->data['Upload']['id'];
$this->Upload->saveField(‘title’, $title);
$this->set(‘title’, $title);
}
}
Thanks for your help.
that was interesting…
Line 1 again:
{?php echo $title;?}
very interesting
@Josey: Thanks for your comment!
Well, you got caught by some automagic ;-) $this->set(‘title’, $title); sets the page title and not a view variable called $title. So you have to rename the “title” key plus the $title variable in the view to something else, and it should work fine.
Hope that helps!
Well that did it!
Thanks for your help and for this walk thru.
@Josey: You are welcome!
Any way of easy debbuging?
Everything works fine for me, easy click and edit inline, but after clicking the button “save”, my database is not changing. Any way of debbuging the way to the controller right after saving ?
@Adrian: I would set debug to 2 (in app/config/core.php) and then check with FireBug which SQL statements are executed.
Hope that helps!
hi
thx for the this post but i have un problem
$this->data is empty, so the function updateTitle is not execute
(“var_dump($this->data)” he take me ‘NULL’
where is the problem???
@Christophe: Hm, did you specify the “id” and “name” properties in your javascript code when calling the editable() function? In the example the values for those properties are “data[Post][id]” resp. “data[Post][title]“. You have to follow the scheme “data[Model][field]“, otherwise the data are not available in $this->data (though they should still be available via $this->params).
Hope that helps!
Hello Cakebaker,
Nice example but i am getting problem in it.
When i click on Save then it is not saving my data. It remains same.
Can you tell me why this is happenning?
i am new to cakePHP.
Thanks
Ankur Gandhi
Hello Cakebaker,
my problem is solved… only one problem was there
i use
$(‘.post’).editable(‘http://localhost/blog/posts/updateTitle’, {
instead of
$(‘.post’).editable(‘/posts/updateTitle’, {
and after that it works.
One more question how can i add effects of Jquery in my HTML page?
for e.g. When i mouseover on my post name then color of its background should be changed.
Thanks in Advance.
Ankur Gandhi
@Chris: How did you hack jeditable to allow multiselects? I can’t believe it doesn’t already…
@Ankur: Thanks for your comments!
I’m glad you could resolve your first question. Regarding your second question, you would accomplish it in a very similar way to what I have shown in this article. Though, instead of calling the editable() function you would call the hover() function, which is part of jQuery. See also http://docs.jquery.com/Events/hover.
Hope that helps!
Nope. Doesn’t work for me. I did exactly this in place edit boost to my Posts basic application and nothing is happening. No inline edit, no nothing. Here is my code if someone out there may be willing to help me with this one:
posts_controller.php
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);
}
}
}
?>
app_controller.php
class AppController extends Controller {
var $helpers = array(‘Html’, ‘Form’, ‘Javascript’);
var $components = array(‘RequestHandler’);
}
?>
default.ctp (the layout)
WebSite Title
link(array(‘jquery-1.2.3′, ‘jquery.jeditable’, ‘example’));
?>
index.ctp (the view that is loaded in $content_for_layout)
<div class=”post” id=”">
update_title.ctp
The example.js is the same.
The .js files are in place…everything is in place, but I have no functionality over my displayed titles.
Nope. Doesn’t work for me. I did exactly this in place edit boost to my Posts basic application and nothing is happening. No inline edit, no nothing. Here is my code if someone out there may be willing to help me with this one:
posts_controller.php
app_controller.php
default.ctp (the layout)
index.ctp (the view that is loaded in $content_for_layout)
update_title.ctp
<?php echo $posttitle;?>The example.js is the same as described in this tutorial.
The .js files are in place…everything is in place, but I have no functionality over my displayed titles
@Progenitus: Hm, I just pasted your code to my test application, and it worked fine. The only change I had to make was modifying the version of jQuery from 1.2.3 to 1.3.2 (the current version) in the layout. Maybe that’s the problem?
And did you try to use a tool like FireBug to figure out what’s going wrong?
Hope that helps!
really nice :)
i got it to work quite fast
but one thing i could not find out:
how can i implement some error handling?
any examples of such callbacks available?
i would like the form field stay in “edit” mode instead of losing the current change and going back to the original one as well as some markup (red) or some alert message with the error specified….
i was thinking about returning an array like
{error=”, value=”} and if the error string is empty everything was alright…
but i still dont know how to get it to work…
thx mark
@mark: Hm, there is an “onerror” callback, though I am not sure it is helpful for what you want to do… Another option could be to submit to a function instead of an url as described on the plugin’s website, and then to do the Ajax call and the error handling “manually”.
Hope that helps!
@cakebaker: Thanks very much for an excellent snippet and tutorial, this is perfect and much easier to use than Ajax::editable (with jQuery loaded).
@alex: Your code was exactly what I was hoping on achieving, I’ve tweaked it a little and it does the job perfectly! Now for a bit of tinkering and that’s Add, Edit, Delete and View all wrapped into 1 page =]
@Stephen: You are welcome!
Very easy to understand – glad you’re the top search for ‘editable cakePHP’. Got it up and running on my system in minutes – cheers to you and Mika Tuupola.
@Momo: You are welcome!
Could anybody explain to me how I would change this to use it as an edit in place on the detail view rather than the index page? And have it work for all fields? Actually — I need to be able to edit the children models of the model whose view I am in… Is that possible with this?
@Josh: Thanks for your comment.
Well, you can use the “edit in place” on a detail view in the same way you use it on the index page.
And to make it work for different fields, have a look at the comment from alex.
Hope that helps!
@cakeaker @alex:
Thanks, that’s got me most of the way there. But after I save, though the database is being updated, it goes to a blank page (with the url of my detail page where I’ve implemented the edit in place…
Can anybody help me out? It’s also adding an “>” to the end of every value on save…
@Josh: Hm. Did you check with Firebug (or a similar tool) what is sent to the server? Do you use the Security component? And can you set “debug” in app/config/core.php to a value greater than 0 and check whether there is some notice/warning?
After save the form field is empty.
@Jens: Hm, do you use the Security component? If that’s the case, your request probably got “blackholed”. You could resolve this issue by defining a blackHoleCallback method:
Hope this helps!