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.
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'=>'{draggedid:element.id}','update'=>'cart'));
echo $ajax->dropRemote('thrashbin',null,array('url' => '/controller/removearticle/','with'=>'{draggedid:element.id}','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'=>'{draggedid:element.id} 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
posted on Tuesday, 29 May 2007 21:25 -
link -
tags: cakephp, php -
path: / -
18 comments
Comments
Posted by Dustin Weber on Thu May 31 05:50:40 2007
Thanks for the tutorial! I finally got it working now
Posted by Anonymous on Mon Jun 4 19:20:38 2007
No problem Dustin, your tutorial was an interesting read nonetheless ;-) And a good starting point.
Anonymous: you're welcome :-)
Posted by Dieter_be on Thu Jun 7 10:28:38 2007
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!
Posted by Sander on Mon Jun 11 18:28:43 2007
Lol, now you mention it :D
I suddenly noticed the CakePHP favicon on your blog :p
Posted by Dieter_be on Tue Jun 12 13:14:31 2007
it's very useful,thanks
Posted by Anonymous on Sat Jul 7 08:54:30 2007
Clear and concise. I finally get it!
Thanks!
Posted by Matt Darby on Sun Jul 22 16:04:13 2007
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.
Posted by KL on Fri Aug 3 06:16:17 2007
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)
Posted by Dieter_be on Fri Aug 3 10:07:52 2007
Thank u very much for this tutorial.
It helps me to understand the ajax helpers drag & drop.
Posted by MyD on Wed Sep 12 09:39:17 2007
This is how a tutorial should be,
short, to the point and working ...
Thanks
Posted by לינוקס on Sat Sep 22 10:56:05 2007
Can you provide a source code for this tutorial
Posted by Sojelee on Wed Oct 10 10:06:48 2007
Hi!
Can you provide a working example of this please?
Thanks
Posted by Software on Thu Dec 6 16:34:50 2007
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
Posted by Dieter_be on Fri Dec 7 21:06:45 2007
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 ;)
Posted by zane matthew on Tue Nov 25 18:12:24 2008
Thanks, good point. I'll fix it
Posted by Dieter_be on Tue Nov 25 22:38:07 2008
Where can I find CakePHP - is this a class of PHP functions or javascript
Posted by Anonymous on Wed Oct 28 04:37:18 2009
Interezante artículo amigo. muy util para los que recien nos iniciamos en cake. y tratamos de trabajar con Ajax....
Posted by jamc on Sat Dec 5 00:15:05 2009
Basic html tags (a,i,b, etc) are allowed, others are sanitized
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
http://www.dustinweber.com