Edit in place with JQuery and CakePHP

Published on and tagged with ajax  cakephp  jquery  view

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 :)

106 comments baked

  • Christophe

    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???

  • cakebaker

    @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!

  • Ankur

    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

  • 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

  • Marc

    @Chris: How did you hack jeditable to allow multiselects? I can’t believe it doesn’t already…

  • cakebaker

    @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!

  • Progenitus

    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.

  • Progenitus

    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

    <?php
      class PostsController extends AppController{
        var $name = 'Posts';
        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);
            }
        	}
      }
    ?>

    app_controller.php

    class AppController extends Controller {
    		var $helpers = array('Html', 'Form', 'Javascript');
    		var $components = array('RequestHandler');
    }
    ?>

    default.ctp (the layout)

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    
    <head>
    	<title>WebSite Title</title>
    <?php
    		echo $javascript->link(array('jquery-1.2.3', 'jquery.jeditable', 'example'));
    
    		?>
    		</style>
    </head>
    <body>
    
    	<?php echo $content_for_layout; ?>
    
    </body>
    </html>

    index.ctp (the view that is loaded in $content_for_layout)
    <?php foreach ($posts as $post): ?>
        <div class="post" id="<?php echo $post['Post']['id']; ?>"><?php echo $post['Post']['title']; ?></div>
    <?php endforeach; ?>

    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

  • cakebaker

    @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!

  • mark

    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

  • cakebaker

    @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!

  • Stephen Speakman

    @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 =]

  • cakebaker

    @Stephen: You are welcome!

  • Momo the Monster

    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.

  • cakebaker

    @Momo: You are welcome!

  • Josh

    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?

  • cakebaker

    @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!

  • Josh

    @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…

  • cakebaker

    @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?

  • Jens

    After save the form field is empty.

  • cakebaker

    @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:

    public function beforeFilter(){
        $this->Security->blackHoleCallback = "isAllowedAjaxRequest";
    }
    
    public function isAllowedAjaxRequest($error){
        if($this->params['controller'] == "posts" && $this->params['action'] == "updateTitle") {
            return;
        } 
    
        die('invalid request');
    }

    Hope this helps!

  • blurp

    zillion thanks for your article!
    works like a charm
    :D

  • kvas

    Hi!
    On my site you can find helper for Ajax in CakePHP.
    Edit in place is also included…
    http://www.cakephp.bee.pl/

  • cakebaker

    @blurp: You are welcome :)

    @kvas: Thanks for the link!

  • CakePHP and AJAX: Inline Editing at Stream of Ry

    […] Editing Guides: The 15-minute blog, Cakebaker, […]

  • CakePHP in place update (with jQuery) plugin | Miljenko Barbir

    […] found a great example, but it only worked if you wished to edit items in displayed in a list-style or table-style […]

  • Agus Saputra

    why the code is not working perfect.. link edit, OK.. but Save not working.. the file not save.. no change..
    sorry if my speak ………….. Im from Indonesia.. thx..

  • cakebaker

    @Agus: Hm, difficult to say what the problem is. Can you check with Firebug (or a similar tool) whether there is a request when you save the changes?

  • Agus Saputra
    cakebaker @ hmm.. OK, I will try.. thx.. once again,.. I need ur help, How using code for count the comments for each post (articles)..
    example:
    
    Article 1
    .... bla.. bla.. ..... bla .. 
    ... bla..bla.. bla... .....
    views (256) | COMMENTS(23)
    ------------------------------------------------
    Article 2
    .... blaa.. bla.... bla......
    .... bla..... bla..... bla......
    views (234) | COMMENTS(34)
    ------------------------------------------------
    ...
    
    how to create script code example read count the COMMENTS? thx...
  • Agus Saputra
    cakebaker @ n also download file script...?
    function download($id = null){
    .
    .
    .
    }
    :)
  • cakebaker

    @Agus: To get the comment count you can either use find(‘count’) or use the counter cache feature: http://book.cakephp.org/view/816/counterCache-Cache-your-count.

    I don’t understand your second comment…

  • Agus Saputra

    hmmm.. dont understand too with ur answer.. maybe the script that I Get from manual book of CakePHP (book.cakephp.org) its so difficult to understand… maybe cause the language diiferent…
    the second comment means how create script code for the force download…

  • cakebaker

    @Agus: Hm, where do you have problems with understanding? Maybe I can clarify it…

    For forcing downloads you might have a look at the media view.

  • Agus Saputra

    actually, I already have a site book.cakephp.org offline versions .. but I think guides are incomplete and did not answer my current problem ..
    but thanks to you who are willing to try for each of my questions .. now all my problems on the CakePHP is completed .. I already have a solution .. if you do not mind, please visit the website at http://agussaputra.co.cc mine. the web is made by using CakePHP .. but still in development .. I want to try to combine with Ajax techniques .. Do not forget to leave a comment .. :)
    thank you very much ..

  • cakebaker

    @Agus: Good to hear you found a solution. Your site looks good, though I don’t understand its content as I don’t speak Indonesian. And the result from Google Translate could be better…

    Anyway, have fun with CakePHP :)

  • Takehiko

    hii, how to create script code for multiple keyword in searching form?

  • cakebaker

    @Takehiko: I’m sorry, but your question is too vague to give you an answer… Maybe SQL’s LIKE and AND operators are what you are looking for?

  • chethan

    it worked for me..
    Thanks for the tutorial… it was really helpful… Thanks a lot..

  • cakebaker

    @chethan: You are welcome :)

  • mark

    what i am still wondering
    is there any new version supporting validation?

    meaning:
    on error it does not close and revert all changes but leaves the text input open simply displaying an error.
    otherwise you would have to re-type it all over again. quite annoying

    mark

  • cakebaker

    @mark: There is an onerror callback you can define for this purpose, see http://www.appelsiini.net/projects/jeditable#comment-51279598.

    Hope this helps!

  • mark

    nice trick! :) thx

  • Nick

    I have added this to my site, but I get an error in Javascript:

    “Error: $(“.click”).editable is not a function
    Source File: #link removed#
    Line: 367″

    I changed it to .post to make it exactly like the example above, but that did not help. Any idea why click would be undefined? I have the JS properly setup in the source as follows:

    $(document).ready(function() {
    $(‘.click’).editable(‘/projects/jeditable/php/echo.php’, {
    id : ‘budget_145’,
    name : ‘amount’
    });
    });

    $6,600.00

    Ideas? Thanks for the help.

  • cakebaker

    @Nick: It sounds like the jeditable plugin is not loaded. Check the generated HTML whether it contains a script tag like

    <script type="text/javascript" src="/js/jquery.jeditable.mini.js"></script>
    

    and make sure the linked file exists.

    Hope this helps!

  • Nick

    @cakebaker: that was it, I had a spelling error. Thought I double checked that. Thanks.

    Another question that was touched above a little bit, how is error handling accomplished? I am doing data validation, etc, but when there is an error, how can I return the original value back to the screen? I got a function working to pop up a flash message stating there was an error, I just can’t get the original data back into the field (I am currently doing a SQL call to pull the original value, but that seems like a waste as the data already exists).

  • cakebaker

    @Nick: The SQL call is not necessary. You can reset the text field in your “onerror” callback function like:

    onerror : function(settings, original, xhr) {
        original.reset();
    }

    I hope this answers your question.

  • Problem integrating jeditable in cakephp. - Programmers Goodies

    […] can go with this for your more […]

  • developer

    hey its a nice tutorial..

    i want to use the same for editing multiple field at the same time.

    I mean when a user clicks on edit button , all the field of that row shd be able to update values. and on click all shd be saved.

    I tried it with the code. bt dint get succes..

    pls help me with the same.

  • cakebaker

    @developer: I don’t know how to accomplish this, but maybe the following article helps: Howto create complex editable fields with JEditable and make it sending all form content.

  • LOL

    This tutorial does not work for me
    I have the same code, the same versions of jquery and jeditable but does not work.
    database and the title is not updated

    please any idea??

    thanks

Bake a comment




(for code please use <code>...</code> [no escaping necessary])

© daniel hofstetter. Licensed under a Creative Commons License