arch bash cakephp conf dauth devops drupal foss git golang information age life linux lua mail monitoring music mysql n900 netlog openstack perf photos php productivity python thesis travel uzbl vimeo web2.0

Drag 'n drop tutorial with the CakePHP 1.2 Ajax helper, Prototype framework and Scriptaculous library


During the development of my thesis I wanted to create a drag 'n drop interface. But I never did anything like that, I never used CakePHP's Ajax helper and neither made I ever use of more advanced functionalities of Scriptaculous/Prototype. Hell I even never touched Ajax before this!

Although there are some basic CakePHP/Ajax tutorials out there, I still had a hard time because some knowledge about Ajax (in CakePHP) was assumed in all of those. After a lot of googling I even found a tutorial called CakePHP: Sortable AJAX Drag & Drops - The Basics
"Perfect!" I thought, until after staring at the article for a long while and I started to notice nowhere in the article "$ajax->drag", "$ajax->drop" or "$ajax->dropRemote" is used. (those are calls on the CakePHP Ajax helper to enhance objects to become draggable, or to become a dropbox where draggables can be dropped into). So the only more or less suited tutorial about drag 'n drop was actually about sorting and didn't use the drag/drop function calls at all. Even though it contains very useful information.

Long story short: I finally got it working (thanks to Krazylegz and kristofer and possibly others too, it has been a while so I may forget someone ;-), and learned a lot in the process. I will share what I learned with you guys so that hopefully it's a bit easier for you then what I had to go through.


CakePHP. I used 1.2 but I think this will work on 1.1 too (because the Ajax helper is in there for a long time. it's even fully documented in the 1.1 manual)
Scriptaculous & Protoype libraries. See the cake manual on how to install these. Don't close this page after installing the libs, because it also explains the possibilities of the Ajax helper and is a reference that you will need! The api reference reveals even more possibilities, but the former page should do.

Let's get started!

Instead of showing a really simple example, I'll give a skeleton example based on a webstore-scenario. You can have multiple articles (draggables) and 2 droppables: a cart and a thrashbin. Dropping an article in the cart adds the article to your order (which I usually keep in the session) and updates the view accordingly, dragging it from the cart into the thrashbin removes it from the session and updates the view too.
I've left out the basics such as sql, models and controller business logic, and focused on the Ajax specifics.

The view-code can be combined in different elements but for simplicity let's assume there is only 1 view file.
Keep in mind that each object where you want to assign some functionality to (such as draggable, droppable) must have a unique DOM id. It doesn't matter if it's a div or span or p or whatever, as long as it has a unique id.

The view looks like this:

drag($article['Article']['id'],array('revert'=>true)); ?> /* the revert thing will make the draggable return to it's original position. Set this to false and the object will stay where you put it. This does not have anything to do with a function call being made btw, that's the job for the draggables */
requestAction('/controller/showcart'); ?> // this call is not necessary. You can use it to fill the
with some content to start with
dropRemote('cart',null,array('url' => '/controller/addarticle/','with'=>'{}','update'=>'cart')); echo $ajax->dropRemote('thrashbin',null,array('url' => '/controller/removearticle/','with'=>'{}','update'=>'cart')); ?> /* these two calls make objects with DOM id's 'cart' and 'thrashbin' droppable. When an object is dropped into them, the actions defined by 'url' are called. The 'with'=>'{} passes the id of the dropped element to the function that is called (on the background, no page refresh or anything like that!). The update thing makes sure that the entire output of the requestAction call is displayed inside the
. So that means that the page will update the part of the page which is specified (dom id 'cart') when the output from the requestAction call is received */ ]]>

The controller would have functions like this:

set('articles',false); /* no articles bought yet */ $this->render('cart'); // (read on to find out more about this view) } function addarticle(){ /* The DOM id of the element that has been dragged into here can be found in $this->params['form']['draggedid']. You can use that id to do something like $this->Article->findById() to add the article to the session. At the end of this function the entire contents of the view file will be returned (and rendered inside the
with DOM id 'cart'.) The layout won't be rendered, only the view, since this is an Ajax call (the difference is autodetected by Cakes RequestHandler) You could do something like this: */ $this->set('articles', $all_bought_articles_from_the_session); $this->render('cart'); } // this function is similar to the one above but instead removes one article from the session and renders the same view ;-) function removearticle(){ } ?> ]]>

The view controller/cart.ctp could look something like this:

  • ]]>

    There you have it. All explanations are inside the sources, I hope it's clear enough. If not, just ask :-)

    Common misconceptions

    From reading many (outdated?) articles about Ajax in cake I noted a lot of information that was not correct. Here they are:

    • It is not necessary to explicity pass the 'ajax' layout as an argument to the render call. Eg you don't need to do this: $this->render('cart', 'ajax'); You can do $this->render('cart'); (or even no explicit render call at all, if the view file is the same as the action name of your controller) Cakes RequestHandler automatically detects when it's dealing with an ajax call, and in that case won't render the layout, only the view.
    • It is not necessary to declare the UTF-8 character encoding in your layout or view
    • You don't need $this->autoRender =false; in the controller. Unless maybe you absolutely don't want to render anything.

    The end

    There you have it. I hope everything is clear. If not, ask on !

    For those who don't have it already, I really recommend The firebug firefox extension. Not only is it a great aid when designing, it's also perfectly suited for debugging Ajax calls. It can show you exactly what happens when you drag an item in a droppable, what request is being made, what is being returned, etc.
    This is explained in this movie:Introduction to Debugging AJAX Application with Firebug


    Sorry about the title of my tutorial (on the Weber Report). What you said makes sense. It really isn't a drag & drop interface so much as a sortable interface. When I get some time, I'll try to fix that.

    Anyways, good write up on a 'true' drag & drop. Keep up the good work!

    Dustin Weber

    Thanks for the tutorial! I finally got it working now

    No problem Dustin, your tutorial was an interesting read nonetheless ;-) And a good starting point.

    Anonymous: you're welcome :-)

    Hi Dieter!

    It seems that beside Gentoo and DT, we also have CakePHP as common interest. Unbelievable, isn't it? :P
    Drag and drop seems very interesting to me, maybe I'll use it in a future project some day. Right now I'm working on some distributed application for school, so no time for sideprojects unfortunately...

    Good luck with your thesis!

    Lol, now you mention it :D
    I suddenly noticed the CakePHP favicon on your blog :p

    it's very useful,thanks

    Clear and concise. I finally get it!


    The different between $this->render('cart', 'ajax'); and $this->render('cart');(or just nothing) is that $this->render('cart'); will use the default layout of the controller, while $this->render('cart', 'ajax'); will use the ajax layout. The default layout usually consists of full HTML (with etc..), while the ajax layout do not. But of course, you can always define the default layout for your controller to suit your need.

    KL, try adding RequestHandler to your use variable, it will detect you're using ajax and use the correct layout automatically. (ajax layout: no extra markup, just the view)

    Thank u very much for this tutorial.
    It helps me to understand the ajax helpers drag & drop.

    This is how a tutorial should be,
    short, to the point and working ...


    Can you provide a source code for this tutorial


    Can you provide a working example of this please?


    The code is ready to be integrated into a CakePHP project. Of course you need Cakephp (and php) skills to do that, but that's not what this article is for

    your site shouldn't be horizontally for long, you should of set a overflow property on your code boxes i think that was the problem, good thing i've got firebug and can do some on the fly cssing to your site others wise i would of left in a heard beat.

    good tutorial tho ;)

    Thanks, good point. I'll fix it

    Where can I find CakePHP - is this a class of PHP functions or javascript

    Interezante artículo amigo. muy util para los que recien nos iniciamos en cake. y tratamos de trabajar con Ajax....





    What is the first name of the guy blogging here?

    This comment form is pretty crude. Make sure mandatory fields are entered correctly.
    Basic html tags (a,i,b, etc) are allowed, others are sanitized