Mootools Drag and Drop Example
This example is outdated and will not work with Mootools 1.0.
So, without an actual demo to play around with, I thought I'd put one together, both to see how easy it'd be to work with and to help demonstrate to others what to expect. What a better example than the drag and drop (especially since I'm finishing up a project that just happened to use drag and drop). Check out the example and check out the source code. I'll be going through and highlighting some of the interesting things.
Doing just enough
One of the things that I noticed in comparison to the Prototype/Scriptaculous (P&S) approach is that there's a basic framework for handling drag and drop and not much more. Where P&S can do much of it for you with just a couple settings tweaks, Mootools creates the hooks and leaves you to pull off the nitty gritty. Right off the bat, I created my new draggable.
$('dragger').addClassName('drag').makeDraggable();
If you've used Prototype, the dollar function should look familiar. As does the addClassName method. Finally, I can make an item draggable using the makeDraggable method. This demonstrates the chainable methods but also the path to which an item is made draggable. So far so good. But wait, my item isn't actually moving. I added position:relative
for my dragger and voila, it's draggable! This is the first of many places where Mootools leaves the details to you.
As a quick sidenote, you can also make an item resizable by using the makeResizable method which uses the same Drag class that is behind makeDraggable. All it does is modify the width and height instead of the left and top properties.
Draggable options
The makeDraggable method can take an options object. Options include callbacks for onStart, onComplete, onDrag, and onSnap. It also accepts an array of droppables which I'll get to in a moment.
var draggableOptions = {
onStart:function()
{
this.el.setOpacity(.5);
},
onComplete:function()
{
// put the element back where it belongs
this.el.setOpacity(1);
this.el.style.left = 0;
this.el.style.top = 0;
}
};
// use your own addEvent instead of window.onload
window.onload = function(){
$('dragger').addClassName('drag').makeDraggable(draggableOptions);
}
With this draggable options object, I change the opacity of the element to 50% when the dragging starts, and set it back to 100%, along with resetting the left and top values to 0. This essentially accomplishes two things Scriptaculous would do for you: ghosting and revert. this
refers to the drag object and el
is the HTML object with which the effect is attached to. For those that have used Moo.fx, this may be familiar.
Droppables
Honestly, drag and drop isn't much fun unless you have droppables. Next, I added the HTML for the droppables. Before hooking in the droppable JavaScript, I noticed that the dragging would drag under the new HTML. Once again, mootools leaves it to you to decide how this stuff should be styled. A quick z-index
on the dragger fixes this right up. Now, onto the JavaScript.
Once again, Mootools differs from Scriptaculous in that there is no Droppable class. But there is a droppable array that is available to us. Simply populate it with a number of elements that you'd like to have as droppables.
var dropitems = document.getElementsBySelector('.item');
draggableOptions.droppables = dropitems;
Two things to mention here: the first is the getElementsBySelector method that is available to use through mootools. It does just like it says and is available through document or any element retrieved via $()
. The second is that I've simply attached my array of items to my draggable options object. As droppables though, they're only useful if they can respond to a number of events. Available to us are onOver, onLeave, and onDrop.
var droppableOptions = {
onOver:function(){
this.addClassName('dragover');
},
onLeave:function(){
this.removeClassName('dragover');
},
onDrop:function(){
this.addClassName('dropped');
this.innerHTML = 'dropped';
}
}
I created a droppable options object that just changes the class names for the most part but on drop also changes the HTML. Now to attach these methods to each of our droppables.
var dropitems = document.getElementsBySelector('.item');
dropitems.each(function(drop){ drop.extend(droppableOptions) });
draggableOptions.droppables = dropitems;
I use the extend method to add the properties of the options object onto each of the drop items.
All done
Check out the example, if you haven't already, and take a look at the source code to see it all together. I haven't done any cross-browser testing so I'd be interested to hear how well this works in your browser.
In the end, how does this compare to Prototype and Scriptaculous? Without paring down the source code, P&S ranks in at over 100k to pull off drag and drop. Mootools on the other hand accomplished it in 17k. (Values are using the uncompressed versions of the source). And so far, I really like the Mootools approach to things. I think we can expect some cool things from this.
Mootools is available from mootools.net. If you like this, feel free to Digg it.
Conversation
It work successfully on IE6, Firefox 1.5.0.6, Opera 9.
On IE7, it gives a error, but works.
I am absolutely loving the Mootools approach to things. I've already used moo.fx before and enoyed the simplicity and small filesize. Defining a class is much more intuitive with Mootools.
Leaving you to define your own options for draggables can be good or bad. Personally, I think it's the simplest way to go. Script.aculo.us does a good job, but it tries to anticipate every option you'd want to use.
I love Prototype, but it's starting to get too bloated to suit my needs. I think I'll be making the switch to Mootools. The modularity of the library and customizable download is definitely the way to go.
I think I REALLY like the way MooTools approaches things. I may have to reconsider my usage of P&S in my apps.
Thanks for taking the time to put this together. It made it easier to see the differences between the libraries.
Very nice exampel right there. I'm trying to learn javascript at the moment, have you got any good [online] references (all the money i can spare for litterature goes to uni-related stuff) for learning javascript?
Regarding the post; I think that many people are ready to make the switch. I think that a part of the wide adoption of prototype is the powerful Rails, Prototype and Scriptaculous combo, but people are also starting to realize that Prototype includes way more than they are in use of, only making page-loads suffer.
fredrik: when i was trying to find the latest prototype.js to download, i found a version that had been split up into the components, each a 2 or 3K JS file. it might be on the rails SVN server somewhere.
Oh yeah, prototypelite or whatever it's called. That's very lightweight indeed, (about 3kb, correct me if im wrong) but I assume you miss out of LOTS of prototype features with that. With Moo you seem to miss out on less, but customize it more yourself. I don't know though since I dont know either.
Trackback
http://blog.ginader.de/archives/2006/09/12/Die-erste-MOOTOOLS-Demo.php
Valerio Proietti hat sich mit der Veröffentlich seiner MOOTOOLS so verausgabt, daß es leider noch nicht für, die so wichtigen, Demos gereicht hat.
Diesem Missstand hat sich gestern Jonathan Snook angenommen. In dem zugehörigen Blogpost erklärt...
Very nice example Jonathan! Saves us the time of trying to make it all work and points out the essential parts (viz. the "position: relative;")
As some are mentionning here, I do like the way of creating new classes and extending classes too. It feels more genuine when one is used to actual programming (js still is scripting).
Looks very interesting, something I'll have to investigate further. I like the idea of having to do a little more work but getting more flexibility, although things like having to set the "position: relative;" on an object that has already had "makeDraggable()" applied to it seems a bit mad.
I've been playing with YUI as an alternative to "P&S" and I like it so far. One thing which has caught my eye is the ease of Targetable affordance (where you can limit drop targets for specific draggables) as in this YUI demo. Any idea how hard this would be to do in MooTools? At first glance the design choice to have a single "droppables" array would seem to preclude this functionality...
Fredrik: Prototype lite was only the code necessary to pull off the effects which certainly meant it left out a lot of cool code. Mootools does a decent job of keeping it lightweight.
MicroAngelo: the single droppables array is per draggable item. Which means that you could define a different set of droppables for each draggable. You could even create different onDrop methods (or have some forking within a single onDrop method) that could behave differently depending on which droppable the draggable was over.
What isn't clear is what happens if you have one droppable for more than one draggable and how the different onDrop states would be handled, since the onDrop is applied directly to the element and not to a droppable object like it is in Scriptaculous. I suppose one could devise a droppable object just for this purpose. And ultimately, that's the flexibility of mootools in that you can choose simple or complex without suffering the size of a large codebase.
Really awesome example! I "stole" your example Javascript and made an example of my own. You'll find the related blog post over at my blog and the example's there as well. I really don't hope you'll hate me for doing this. If you'd like me to remove the example or go code my own I will gladly do so, but your example was a great base for me to build on since I'm not that great at Javascript.
Many thanks!
Great example, Jonathan. I've written a post about the beautiful ways to extend mootools. I'll be writing some more posts on the library's cool new features.
Yeah..., now we only need more examples that make we understand so much better this wonderful new "old" world =]
I've posted a sample how how to create a simple lightBox example using the new mooTools.
first of all thanx for a great tutorial...
I also have decided to add my two cents, by editing the script to use css classes instead of opacity in the js.
Check out the post at my site.
It's interesting what folks expect now from a quality Drag and Drop API. The essential "interesting moments" are becoming more standardized such as "startDrag, endDrag, onDrag, onDragOver, onDragOut, onDragDrop..." etc. It seems like Moo has done a good job at delivering that :)
Well as others have said, great example (I'm in the process of breaking down some examples myself and will post them as soon as I've finished (already got a Resize, ResizeWidth only, ResizeHeight only in place).
One question though, anyone know how to make an object UNdraggable, once you've made it draggable?
Thanks
Mike B.
MikeB: there's no "undrag" feature but a quick test that serves its purpose is to remove the onmousedown event from the draggable. You can do this either via the onComplete of the draggable event using
this.el.onmousedown = null
or in the onDrop event of the droppable.onDrop:function(o){o.onmousedown = null}
The o object is the draggable div. It gets passed in as the first parameter when onDrop fires. Therefore, just nullify the onmousedown and voila, you can no longer drag.
Kewel, thanks Jonathan for such a quick response. I kinda figured that there was no "undrag" when looking at the code but wasn't sure if I missed something or not and the thought of just "nulling" out the onmousedown was a bit disturbing from a memory leak perspective (since in the code I'm putting together I want to add back the "draggable" ability at a later time to the objects. But I'll give it a try and see what happens.
Thanks again
Mike B.
I have attempted to try this example against the latest SVN drop (revision 60) and seems something has changed. The "this" keyword context in the drop target events for "droppableOptions" no longer references the element, but the draggable Object. Needless to say, this causes the addClassName, removeClassName to throw out errors. Has anyone had the same result?
@Jonathan Snook && MikeB: I have added dragObject.pause and resume (thanks for the suggestion!).
And now the object is passed as the second argument. for example you could do something like this:
$('myDropElement').onDrop = function(elementDropped, dropObject){
elementDropped.setOpacity(0.5);
dropObject.pause();
}
This way is also easier to manage the "one droppable/many draggable" scenario.
@mike kidder: in the new revision I have fixed this. I overlooked the problem, and I agree that the this keyword should refer to the current element for the onDrop/onLeave/onOver events.
Hi all. I've added a new sample using the mooTools. This is a port of the reflector effect. It's amazing how it was easy to do.
@Valerio: The only problems I had was with the getBrother, because it fetches elements on not the real next/previous sibling. An additional parameter to this function would be great, one that could tell if we wanted the elements or non elements to be found.
Great, thank you for this sample.
I am a beginner user of mootools and I have a lot of questions about their use, but...
only one thing, Is there something like prototype's 'Event.observe()' in mootools framework?
Thanks!!!!
Hi ppl. I've made an extended Drag&Drop example with a Drag element class, which allows multiple drag elements (and multiple drag containers) to be used. Right now it has only two containers, but easily you can use say five containers.
I also wrote a small article about it, but it's in Bulgarian so i won't share it with you :P
The example only is here:
http://www.bundyo.org/mootools/
Nice, and sorry it this comment it's off-topic but your design looks different in FF and IE.
Greetings and thanks for the article for mootools!
It's works ok on FreeBSD 5.4 via Mozilla Firefox 1.0.3
Opera 8.51 / FreeBSD 5.4
-----
A little error the first time that select the item to drag, it's appear that TOP+=SIZE OF ITEM , but the rest its ok.
A better example of 2-dimensional sortable list (multi columns and rows) based this time upon the Sortables class from Mootools. I rewrited it to take care of the x axis. You can find the example here :
http://chatalors.chez-alice.fr/sortables.html
It works perfect in Firefox and seams perfect in IE too, but you should read my post here about possible closures firing problems with IE on refreshing/reloading page :
http://freewebsfarms.com/forums/viewtopic.php?pid=3029#p3029
Valerio, I saw your comments in entry # 22 (Thanks for the suggestion), however did you implement this in the mootools code or is this something I need to add to my code (can't find the "pause" or "resume" in the current (e.g. R77) or even latest SVN (R82) of the code.
Thanks again
Mike B.
Oh and not to be greedy <grin> but can the pause/resume be done w/o a "dropObject"? In the code I'm working on I'm not "dropping" the item being dragged into a specific container, just dragging it around the screeen for positioning (sort of like the "mooglets" example). although I suppose I could use the Body element as a "dropObject" now couldn't I?
Mike B.
The drag and drop is very useful which resent here.It is really amazing.
But my requirements is to make two frames and provide drag and drop component.It should be just like add playlist in media player.
Please give sugesstion by giving code for dragging elements betwwen two frames.
-Raju
raju: doing a drag and drop across frames won't really be possible with any of the existing libraries (I suspect). It's probably best to build something like this from scratch. You'll need the two documents to be able to communicate between each other to track whether a drag event has started in one document as the mouse enters the other.
Nice demo, clean and simple.
The question is - how to introduce a drag proxies, in the way YUI does it?
Thanks,
Temuri
Temuri: Unfortunately, drag proxies aren't really possible with the mootools library in its current incarnation. You'd have to rewrite the initialization method and the addStyles method to tie in a proxy element. My thought is that you'd probably be better off to stick with YUI or Scriptaculous.
You can do Proxies. Just add this to your onStart function.:
this.element = this.element.clone().injectInside(document.body);
Sory, forgot some stuff
this.elementOrg = this.element;
this.element = this.element.clone().setStyles({
position: 'absolute',
top: this.element.getTop() + 'px',
left: this.element.getLeft() + 'px',
opacity: '0.6'
}).injectInside(document.body);
Drag & Drop swap positions example?
Have seen alot of examples of drag and drop sortable lists, but no examples where the dragged object swaps positions with the object it is dropped onto.
If your trying to reorder images, it would be nice if all the other images didn't start sliding around and reordering as soon as you start dragging. Kind of counterintuitive.
Hello, great tutorial.
but i cant get it to work on IE, i copy and paste your example page and edited the js to load my mootools js ( ver 83 ).
and firefox keep generating error on line 22 and 27 ( this.el.setOpacity )
problem solved :)
just add top and left style for the dragger
I really like Mootools, but I can't seem to find any clear and descriptive documentation on it, so I am really glad you made this page!
I am having trouble with IE and Opera because most of the time Mootools only works in Firefox!!
I would like to see a lot more documentation on the graphical effects and transitions Mootools has to offer, because I can't seem to get any to work.
If anybody finds any good tutorials or documentation on Mootools that you think I may have missed, feel free to email me: info [at] olivertreend [dot] com. Thanks!
nice one
normally if we have a big list we need to scroll. but it is not working while dragging.
You might want to let your readers know that this example is out of date and will no longer work with mootools v1.0. The draggables code can be made towork pretty easily by changing this.el to this.element.
However, due to the new fireEvent used in the Drag.Base, you'll have to register the onOver, onLeave, onDrop events separately rather than simply extending them.
So instead of drop.extend(droppableOptions), do:
drop.addEvents(droppableOptions);
And you'll also have to change 'onOver' to 'over'.
I see this as a bug in the Drag.Base implementation, and I have filed it accordingly. So this will probably be just a temporary fix.
Cheers,
James
to James Chen
tnx very very much for update i lost hours to find this out
regards
First, It's great, works perfectly on IE 6 and Firefox.
Second, i edit the html and a combo next to the text Item 1 and, when dragging the div it doesn´t stay over the combo. I know this is a IE bug and wahtwvere but, is ther a way to work around with this bug?.
Greetings
Very useful example here. I recently found your blog as I've been teaching myself cakephp in the last few weeks. I'm impressed.
I like the amount that mootools does for you. Its lightweight and easy to extend it to do what you need.
Thanks for the demo, its cool (there's a javascript error though when you start to drag in your sample).
Someone mentioned swapping drag and drops? I saw this on YouTube a about a month ago and asked the guy about how he did it. He said he used Mootools but he wouldn't let me have the code [yet]. It's worth looking at because the example shows that he drags and drops before, after and even swaps with other elements.
Looks cool!
http://nl.youtube.com/watch?v=pvvmqP89lb8