In my last post [clickie] I discussed how to implement nested dragging, in this post I’m going to extend it to dynamically loading data with the nested dragging. So you should probably read the other one first. How exactly will this work? There will be a parent node (draggable) which can have an infinite number of child nodes (draggableChild) which in turn can have an infinite number of children and so on. How is this done with nested dragging?
First: Imagine that each parent node has a header and a list of it’s children’s headers, and that each child node can either be another parent node or a child page. The child page consists of header (which appears in the parent page too) and content.

Parent Page Layout

Child Page Layout
Second: It works like this, every time you drag out a child header from it’s parent it’s content is loaded.
Step 1
The parent/child page must have a certain format, which is basically a header section and content section. Any parent page has the exact same skeletal layout, just different content (other divs instead of lorem ipsum). A very Important thing to keep in mind is that the script and styles must appear once in the very first parent. Or the page that dynamically loads the box itself (goto step 6).
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce quis lacus sapien, nec tincidunt purus.
Step 2
There is hundreds of ways to do the next part. So I will do the first one that comes to mind. The headers of the child pages must be added to their perspective parents. So for each child a div will be added for it with the class “draggableChild” and a title that contains the child page url (preview).
Sample Child 1
The HTML
Sample Child 1
Sample Child 2
Sample Child 3
Sample Child 4
Step 3
You will now notice that there is a slight bug: The dragged box is not above the other boxes… To fix this we will add this JQuery .draggable() option “stack”
$( ".draggable" ).draggable({ stack: ".draggable" });
Step 4
The content of the child page should load when we drag out the child from it’s parent. To do this the script from the previous post must be tweaked. After the drag finishes (stop:) Two things must be added: (1) load the page using the .load(), this will be done in two steps: load the header then load the content (2) remove the draggableChild class and add the draggable class (preview)… For further reading on the .load() clickie
$(this).load($(this).attr('title')+' .header',function(){ //loads the header, after it is done it executes the rst
$(this).append(''); //adds a temporary Div, as the load() replaces the content
$('#temp').load($(this).attr('title')+' .content',function(){ //loads the content
$('#temp').replaceWith($('#temp').html()); //replaces the temporary div with the content.
});
$(this).removeClass('draggableChild');
$(this).addClass('draggable');
});
The script will be
$('.draggableChild').draggable({
stack: ".draggable",
stop:function(event,ui){
var pos = $(this).position();
var pos2 = $(this).closest('.draggable').position();
$(this).css({
position : "absolute",
marginLeft : 0,
marginTop : 0,
top : pos2.top + pos.top,
left : pos2.left + pos.left,
});
$('body').append($(this));
$(this).draggable({stop:function(event, ui){[,stack: ".draggable" });
$(this).load($(this).attr('title')+' .header',function(){
$(this).append('');
$('#temp').load($(this).attr('title')+' .content',function(){
$('#temp').replaceWith($('#temp').html());
});
$(this).removeClass('draggableChild');
$(this).addClass('draggable');
});
}
});
Step 5
This script essentially works if there is only have two levels. With more levels this happens preview. Why does this happen? Because the newly added divs are not binded to the draggable() action. So to solve this we will use the .live(), it basically binds a certain action and event to an object which is present on the page now or maybe be present on the page in the future (preview). Further reading: clickie The scripts will be further modified as follows:
$('.draggable').live('mouseover',function(){
$(this).draggable({ stack: ".draggable" });
});
$('.draggableChild').live('mouseover',function(){
$(this).draggable({
stop:function(event,ui){
var pos = $(this).position();
var pos2 = $(this).closest('.draggable').position();
$(this).css({
position : "absolute",
marginLeft : 0,
marginTop : 0,
top : pos2.top + pos.top,
left : pos2.left + pos.left,
});
$('body').append($(this));
$(this).draggable({stop:function(event, ui){},stack: ".draggable" });
$(this).load($(this).attr('title')+' .header',function(){
$(this).append('');
$('#temp').load($(this).attr('title')+' .content',function(){
$('#temp').replaceWith($('#temp').html());
});
$(this).removeClass('draggableChild');
$(this).addClass('draggable');
});
}
});
});
Step 6
What if you want a link on your page that opens one of these boxes?? You will first have to remove the scripts and styles from the first parent, and put it on the page you want. Second we will need a function that will open the box. We will call this function openBox(url,el) where url is the url of the box to be loaded, and el is the id of place where you want the box to appear. (preview
function openBox(url,el)
{
$('#' + el).append('');
var element = $('#' + el + ' #myTemp')
element.load(url, function()
{
element.children().attr('title', url);
element.children().css('z-index','4');
element.replaceWith(element.html());
});
}
The HTML of the front page
And we are done!
So far this is the basic functionality of dynamically loading content with drag and drop, but there is so many features that can be added, docking/minimizing/maximizing/closing/reverting a little sample.