Combining Selectables And Draggables Using jQuery UI
There are two powerful and fun elements that the jQuery UI provides. When both of them work together you will be able to come up with some creative web application uses for them. The two I am going to be covering are:
- UI Selectable – Demo – Documentation
- UI Draggable – Demo – Documentation
I am sure you all want to see what the final product will look like, check it out.
To start working with the jQuery UI you are going to need to add the following files to the head of your document:
- jquery-1.2.6.min.js – the main core jquery framework
- ui.core.js – the UI core javascript
- ui.draggable.js - the draggable javascript
- ui.selectable.js – the selectable javascript
Before we get started let me just say, thanks a ton to Richard Worth who has helped develop the jQuery UI and provided a ton of help to me last year trying to get this to work, and boom here is the working copy, you can find Richards blog here.
The jQuery UI adds classes for different mouse events, for instance:
- jQuery UI Draggable
- .ui-draggable – the class it adds you when create the draggable(); object
- .ui-draggable-dragging - the class it adds when you are dragging the object around the page
- jQuery UI Selectable
- .ui-selectee - the class it adds when you create the selectable(); object
- .ui-selectable – the class it adds when you select the object
- .ui-selecting – the class it adds when you click and start to create the bounding box around the elements you wish to select, once you let go, it becomes .ui-selectable
That is the basic structure how how the jQuery UI draggable and selectable generates classes to manipulate change for each action.
I am going to be using console.log(); to report what the code is doing after different steps throughout the page. Make sure you have Firebug installed if you are on Firefox. If you are unsure what console.log() does view the documentation. Be sure that if you use this technique in a real world example, remove the console.log() functions to decrease page loading time. This neat little function allows us to see what our code is doing, we can call:
console.log(variable);
When we open up the page and open Firebug, it will print out what the variable contains, it is a great tool for debugging, keep it handy.
Now that we have the understanding on how it works with different classes, lets start looking at the code that makes it work. I have commented it to make it easier for you to translate on your own time.
The first bits of the code
// creates the selected variable
// we are going to be storing the selected objects in here
var selected = $([]), offset = {top:0, left:0};
console.log("This is the value of selected when it is created " +selected + "");
As you can see from above, our first line creates the variable selected and is able to store numerous values because we are setting up an array for this variable. And the offset, resets the top and left values. If you use console.log it will output: Object length=0 prevObject=Object jquery=1.2.6 notice the length is 0 that is fine we haven’t selected any items yet.
// initiate the selectable id to be recognized by UI
$("#selectable1").selectable();
This part above, calls the selectable to generate the selectable region. NOTE: that #selectable is container and is the box not each element we are selecting.
The following part is important because, this is the where we start to hook up selectables with the draggables.
// declare draggable UI and what we are going to be doing on start
$("#selectable1 div").draggable({
start: function(ev, ui) {
$(this).is(".ui-selected") || $(".ui-selected").removeClass("ui-selected");
console.log("The value of 'this' currently is: "+this);
selected = $(".ui-selected").each(function() {
var el = $(this);
el.data("offset", el.offset());
$(this).text("Selected and dragging object(s)");
});
console.log(selected);
offset = $(this).offset();
},
The part below, tells the draggable UI to create every element within to have dragging.
$("#selectable1 div").draggable({
$(this).is(".ui-selected") || $(".ui-selected").removeClass("ui-selected");
console.log("The value of 'this' currently is: "+this);
This next section above resets the select and drag, by removing the ui-selected class, when we output using console.log, to see the value of this is The value of ‘this’ currently is: [object HTMLDivElement].
selected = $(".ui-selected").each(function() {
var el = $(this);
console.log("The value of el is: "+el);
el.data("offset", el.offset());
$(this).text("Selected and dragging object(s)");
});
Now we are finally working with the selected variable we created at the start of this, we are to run through each element with the class of ui-selected. We are going to be storing the value of $(this) in the variable el, to make it easier to call and to work with the offset(); property later on.
el.data("offset", el.offset());
$(this).text("Selected and dragging object(s)");
We are going back to out el variable and working with the data object and the offset object. The offset object returns two integer values: top and right. The definition of the offset(); from the jQuery documentation is: Get the current offset of the first matched element relative to the view port.
The other line, changes the text of the elements to let us know that we have selected and are now dragging the objects stored in the variable selected.
Now that we have called offset we want to store it in the variable offset, for each DOM elements selected. The code that follows this part is below:
console.log("The new value of selected is now "+selected);
offset = $(this).offset();
console.log("The value of top value is "+offset.top+" and the left value is "+offset.left);
We have another console.log() to print out the selected value and it is storing the DOM element. Next we create the variable offset and store the offset() of the elements, I have printed the top and left values using console.log() above, the output is similar to: The value of top value is 207 and the left value is 672.
The next section below is the section of code that handles what is going to go on while we are dragging our selected elements. This part is also very important because we are bringing back the values of offset with the current values of the draggable ui, it stores the ui properties in ui.position.top and ui.position.left. Further down the code we will use the offset values to update the CSS top and left properties of the selected elements.
drag: function(ev, ui) {
var dt = ui.position.top - offset.top, dl = ui.position.left - offset.left;
console.log("The value of dt is "+dt);
selected.not(this).each(function() {
var el = $(this), off = el.data("offset");
el.css({top: off.top + dt, left: off.left + dl});
});
},
We are creating the variable dt on the second line there and this value is equal to ui.position.top – offset.top and we are also creating the variable dl that is dl = ui.position.left – offset.left. So we have:
- var dl – working with the x axis or the left coordinates
- var dt – working with the y axis or the top coordinates
Lets add a console.log to see what these values are before we do the math. Add the following code to see what our variables and math are doing:
console.log("The value of dt is "+dt+" and is equal to "+ui.position.top+" - "+offset.top);
console.log("The value of dl is "+dl+" and is equal to "+ui.position.left+" - "+offset.left);
console.log("The value of ui.position.top is "+ui.position.top);
console.log("The value of ui.position.left is "+ui.position.left);
console.log("The value of offset.left is "+offset.top);
console.log("The value of offset.left is "+offset.left);
When you run the code the console.log() outputs the following:
The value of dt is 37 and is equal to 237 - 200
The value of dl is 152 and is equal to 352 - 200
The value of ui.position.top is 237
The value of ui.position.left is 352
The value of offset.top is 200
The value of offset.left is 200
Notice what the code is printing out, it is taking the ui.position.top and subtracting the value of offset.top and giving us the difference to equal variable dt. We do this math so we can update the top and left CSS properties in the next section of code, if we didn’t do this math, we would select and drag our elements and they would move sporadically on the page.
Next we are going to cover the other each function that loops through each of the selected elements expect $(”this”):
// take all the elements that are selected expect $("this"), which is the element being dragged and loop through each.
selected.not(this).each(function() {
// create the variable for we don't need to keep calling $("this")
// el = current element we are on
// off = what position was this element at when it was selected, before drag
var el = $(this), off = el.data("offset");
el.css({top: off.top + dt, left: off.left + dl});
});
So we have the last big piece of code to make this script work. Like I said, you have the each function that runs through each element expect $(”this”), then we create two variables:
- el – which is the current element we are on
- off – which is the position of the elements when they were selected, before any type of movement and drag
The last segment: we are going to be adding or subtracting (we will subtract if the dt or dl is negative). The dl stands for delta left and dt stands for delta top. For instance lets set something up:
The current element we are on start at the coordinates: 10, 30, now we drag that to: 8, 15. Now lets run the math, the new position of the element is: 2, 15. Say, you drag it again, it runs the loop once again, and the off will be 2, 15 and the new value will be wherever the new coordinates are subtract the total delta from when the drag started until now, not just the last mouse movement.
Now that we did the math and we have captured the new value, update it is the css property and plug in the top and left coordinates.
So what did you think of it? Pretty interesting effect when you combine both of those UI elements to create select and drag. Share your thoughts and make sure to bookmark using the button below. Any improvements? Contact me.
Enjoy!
other related posts...
- Using the jQuery UI Slider
- jQuery Search And Highlight
- jQuery Timeout Function
- Working with the jQuery live function
- Create a jQuery Accordion – remain open after page load

I guess now the task is getting a droppable() to accept them simultaneously… :-]
@Wes its true! it would make using those two UI elements flawless. I have been talking to Richard Worth one of the developers on the UI and that is their goal to get those two elements playing together as one function, so hopefully all in good time.
I don’t understand this article -
this demo doesn’t work either in FFox 3, Opera 9.64 or IE 7….
@ReTox I just gave it a shot and seemed to work fine for me. Did you get any errors in Firebug?
In IE 7 the javascript error is “‘console’ is undefined.” It doesn’t work for me either in FF or IE 7. Firebug doesn’t report an error but IE 7 does. Looking forward to seeing the end product for this functionality especially if its included for 2 connected sortables lists.
[...] View Tutorial No Comment var addthis_pub=”izwan00″; BOOKMARK This entry was posted on Monday, June 8th, 2009 at 4:10 am and is filed under Javascript Tutorials. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site. [...]
It was hard to get it work from the code snippets above but thanks for sharing.
// creates the selected variable
// we are going to be storing the selected objects in here
var selected = $([]), offset = {top:0, left:0};
console.log(”This is the value of selected when it is created ” +selected + “”);
// initiate the selectable id to be recognized by UI
$(”#selectable1″).selectable({
filter: ‘div’,
});
// declare draggable UI and what we are going to be doing on start
$(”#selectable1 div”).draggable({
start: function(ev, ui) {
selected = $(”.ui-selected”).each(function() {
var el = $(this);
el.data(”offset”, el.offset());
//$(this).text(”Selected and dragging object(s)”);
});
if( !$(this).hasClass(”ui-selected”)) $(this).addClass(”ui-selected”);
//console.log(”The value of ‘this’ currently is: “+this);
console.log(selected);
offset = $(this).offset();
},
drag: function(ev, ui) {
var dt = ui.position.top – offset.top, dl = ui.position.left – offset.left;
console.log(ui.position.top,offset.top);
//console.log(”The value of dt is “+dt);
// take all the elements that are selected expect $(”this”), which is the element being dragged and loop through each.
selected.not(this).each(function() {
// create the variable for we don’t need to keep calling $(”this”)
// el = current element we are on
// off = what position was this element at when it was selected, before drag
var el = $(this), off = el.data(”offset”);
el.css({top: off.top + dt, left: off.left + dl});
});
}
});
This is how i could get it running.
Did the code in the demo file help you at all? Also, thanks for posting your working code. Glad you got it working.
Ryan, the code works great–but only if Firebug is enabled. I almost passed it up but since you are ranking #1 on Google for this term I gave it a few shots and eventually discovered the reason when I enabled Firebug to see if I could figure out where it was broken.
It’s probably because you’re using console.log().
Hope this helps you help the other readers!
Can you at least provide a working demo?
If it doesn’t work with FF, IE, or Opera, I don’t see much point in even bothering with the code.
[...] Combining Selectables And Draggables Using jQuery UI [...]
[...] Combining Selectables And Draggables Using jQuery UI [...]
[...] Combining Selectables And Draggables Using jQuery UI [...]
[...] Combining Selectables And Draggables Using jQuery UI [...]
Great demo!
Is there any way to make it work with jQuery 1.4?
It does not work with 1.4 and I can’t figure it out why.
Thank you.