YUI 3.x Home -

Site Search (YDN & YUIBlog):

# YUI Library Examples: Drag & Drop: List reorder w/Bubbling

## Drag & Drop: List reorder w/Bubbling

This example shows how to make a sortable list using Custom Event Bubbling.

View example in new window.

- Item #1
- Item #2
- Item #3
- Item #4
- Item #5

- Item #1
- Item #2
- Item #3
- Item #4
- Item #5

### Setting up the lists

First we will make some lists that we want to make sortable.

    <div id="play">    <ul id="list1">        <li class="list1">Item #1</li>        <li class="list1">Item #2</li>        <li class="list1">Item #3</li>        <li class="list1">Item #4</li>        <li class="list1">Item #5</li>    </ul>    <ul id="list2">        <li class="list2">Item #1</li>        <li class="list2">Item #2</li>        <li class="list2">Item #3</li>        <li class="list2">Item #4</li>        <li class="list2">Item #5</li>    </ul></div>

    <div id="play">
        <ul id="list1">
            <li class="list1">Item #1</li>
            <li class="list1">Item #2</li>
            <li class="list1">Item #3</li>
            <li class="list1">Item #4</li>
            <li class="list1">Item #5</li>
        </ul>
        <ul id="list2">
            <li class="list2">Item #1</li>
            <li class="list2">Item #2</li>
            <li class="list2">Item #3</li>
            <li class="list2">Item #4</li>
            <li class="list2">Item #5</li>
        </ul>
    </div>

<div id="play"> <ul id="list1"> <li class="list1">Item #1</li> <li class="list1">Item #2</li> <li class="list1">Item #3</li> <li class="list1">Item #4</li> <li class="list1">Item #5</li> </ul> <ul id="list2"> <li class="list2">Item #1</li> <li class="list2">Item #2</li> <li class="list2">Item #3</li> <li class="list2">Item #4</li> <li class="list2">Item #5</li> </ul> </div>

### Setting up the YUI Instance

Now we need to create our YUI instance and tell it to load the `dd-constrain`, `dd-proxy` and `dd-drop`, modules.

    YUI().use('dd-constrain', 'dd-proxy', 'dd-drop', function(Y) {

    YUI().use('dd-constrain', 'dd-proxy', 'dd-drop', function(Y) {

YUI().use('dd-constrain', 'dd-proxy', 'dd-drop', function(Y) {

### Making the Nodes Drag Instances and Drop Targets

Now we have our YUI instance ready, we can make the list items draggable. We will do this using `Y.Node.all`

We will be passing the selector string `#play ul li` to `Y.Node.all` to have it return us a `NodeList` of the li's in our 2 lists. Using this selector syntax we will be able to add new list markup to the `#play` div and not have to change our code.

Then we will walk that `NodeList` and create our draggable Nodes.

Note that we are setting the following configs on the Drag instance: `proxy, moveOnEnd, constrain2node, target`.

    //Get the list of li's in the lists and make them draggablevar lis = Y.Node.all('#play ul li');lis.each(function(v, k) {    var dd = new Y.DD.Drag({        node: v,        //Make it Drop target and pass this config to the Drop constructor        target: {            padding: '0 0 0 20'        }    }).plug(Y.Plugin.DDProxy, {        //Don't move the node at the end of the drag        moveOnEnd: false    }).plug(Y.Plugin.DDConstrained, {        //Keep it inside the #play node        constrain2node: '#play'    });});

    //Get the list of li's in the lists and make them draggable
    var lis = Y.Node.all('#play ul li');
    lis.each(function(v, k) {
        var dd = new Y.DD.Drag({
            node: v,
            //Make it Drop target and pass this config to the Drop constructor
            target: {
                padding: '0 0 0 20'
            }
        }).plug(Y.Plugin.DDProxy, {
            //Don't move the node at the end of the drag
            moveOnEnd: false
        }).plug(Y.Plugin.DDConstrained, {
            //Keep it inside the #play node
            constrain2node: '#play'
        });
    });

//Get the list of li's in the lists and make them draggable var lis = Y.Node.all('#play ul li'); lis.each(function(v, k) { var dd = new Y.DD.Drag({ node: v, //Make it Drop target and pass this config to the Drop constructor target: { padding: '0 0 0 20' } }).plug(Y.Plugin.DDProxy, { //Don't move the node at the end of the drag moveOnEnd: false }).plug(Y.Plugin.DDConstrained, { //Keep it inside the #play node constrain2node: '#play' }); });

### Making the List Drop Target's too

We need to make the UL nodes a Drop Target so we can catch drops on the empty space of the list. Using this selector syntax we will be able to add new list markup to the `#play` div and not have to change our code.

    //Create simple targets for the 2 lists..var uls = Y.Node.all('#play ul');uls.each(function(v, k) {    var tar = new Y.DD.Drop({        node: v    });});

    //Create simple targets for the 2 lists..
    var uls = Y.Node.all('#play ul');
    uls.each(function(v, k) {
        var tar = new Y.DD.Drop({
            node: v
        });
    });

//Create simple targets for the 2 lists.. var uls = Y.Node.all('#play ul'); uls.each(function(v, k) { var tar = new Y.DD.Drop({ node: v }); });

### Using Event Bubbling

By default, all Drag and Drop instances bubble their event's up to the DragDropMgr. In this example we are assuming that there are no other Drag Operations in this YUI Instance.

### Start Drag Event

The first thing we will do is handle the drag:start event. In this event, we will setup some styles to apply to the `node` and `dragNode` of the current Drag instance.

We will also be copying the `innerHTML` of the `node` and copying that to the `innerHTML` of the `dragNode`.

It should be noted, that doing this will also copy any `id`'s of the nodes inside the `node`. So if you are using this on something that is `id` based, you may need to remove the `id`'s of the nodes inside the `node` that is being dragged.

    Y.DD.DDM.on('drag:start', function(e) {    //Get our drag object    var drag = e.target;    //Set some styles here    drag.get('node').setStyle('opacity', '.25');    drag.get('dragNode').set('innerHTML', drag.get('node').get('innerHTML'));    drag.get('dragNode').setStyles({        opacity: '.5',        borderColor: drag.get('node').getStyle('borderColor'),        backgroundColor: drag.get('node').getStyle('backgroundColor')    });});

    Y.DD.DDM.on('drag:start', function(e) {
        //Get our drag object
        var drag = e.target;
        //Set some styles here
        drag.get('node').setStyle('opacity', '.25');
        drag.get('dragNode').set('innerHTML', drag.get('node').get('innerHTML'));
        drag.get('dragNode').setStyles({
            opacity: '.5',
            borderColor: drag.get('node').getStyle('borderColor'),
            backgroundColor: drag.get('node').getStyle('backgroundColor')
        });
    });

Y.DD.DDM.on('drag:start', function(e) { //Get our drag object var drag = e.target; //Set some styles here drag.get('node').setStyle('opacity', '.25'); drag.get('dragNode').set('innerHTML', drag.get('node').get('innerHTML')); drag.get('dragNode').setStyles({ opacity: '.5', borderColor: drag.get('node').getStyle('borderColor'), backgroundColor: drag.get('node').getStyle('backgroundColor') }); });

### End Drag Event

In this event, we will reset some of the styles set in the drag:start event.

    Y.DD.DDM.on('drag:end', function(e) {    var drag = e.target;    //Put out styles back    drag.get('node').setStyles({        visibility: '',        opacity: '1'    });});

    Y.DD.DDM.on('drag:end', function(e) {
        var drag = e.target;
        //Put out styles back
        drag.get('node').setStyles({
            visibility: '',
            opacity: '1'
        });
    });

Y.DD.DDM.on('drag:end', function(e) { var drag = e.target; //Put out styles back drag.get('node').setStyles({ visibility: '', opacity: '1' }); });

### Drag Event

In this event, we will track the up/down movement for later use.

    Y.DD.DDM.on('drag:drag', function(e) {    //Get the last y point    var y = e.target.lastXY[1];    //is it greater than the lastY var?    if (y &lt; lastY) {        //We are going up        goingUp = true;    } else {        //We are going down..        goingUp = false;    }    //Cache for next check    lastY = y;});

    Y.DD.DDM.on('drag:drag', function(e) {
        //Get the last y point
        var y = e.target.lastXY[1];
        //is it greater than the lastY var?
        if (y &lt; lastY) {
            //We are going up
            goingUp = true;
        } else {
            //We are going down..
            goingUp = false;
        }
        //Cache for next check
        lastY = y;
    });

Y.DD.DDM.on('drag:drag', function(e) { //Get the last y point var y = e.target.lastXY[1]; //is it greater than the lastY var? if (y < lastY) { //We are going up goingUp = true; } else { //We are going down.. goingUp = false; } //Cache for next check lastY = y; });

### Over Drop Event

In this event, know which Target we are over, so we add the Drag node to the list either above or below the current Drop Target.

    Y.DD.DDM.on('drop:over', function(e) {    //Get a reference to out drag and drop nodes    var drag = e.drag.get('node'),        drop = e.drop.get('node');     //Are we dropping on a li node?    if (drop.get('tagName').toLowerCase() === 'li') {        //Are we not going up?        if (!goingUp) {            drop = drop.get('nextSibling');        }        //Add the node to this list        e.drop.get('node').get('parentNode').insertBefore(drag, drop);        //Resize this nodes shim, so we can drop on it later.        e.drop.sizeShim();    }});

    Y.DD.DDM.on('drop:over', function(e) {
        //Get a reference to out drag and drop nodes
        var drag = e.drag.get('node'),
            drop = e.drop.get('node');

        //Are we dropping on a li node?
        if (drop.get('tagName').toLowerCase() === 'li') {
            //Are we not going up?
            if (!goingUp) {
                drop = drop.get('nextSibling');
            }
            //Add the node to this list
            e.drop.get('node').get('parentNode').insertBefore(drag, drop);
            //Resize this nodes shim, so we can drop on it later.
            e.drop.sizeShim();
        }
    });

Y.DD.DDM.on('drop:over', function(e) { //Get a reference to out drag and drop nodes var drag = e.drag.get('node'), drop = e.drop.get('node'); //Are we dropping on a li node? if (drop.get('tagName').toLowerCase() === 'li') { //Are we not going up? if (!goingUp) { drop = drop.get('nextSibling'); } //Add the node to this list e.drop.get('node').get('parentNode').insertBefore(drag, drop); //Resize this nodes shim, so we can drop on it later. e.drop.sizeShim(); } });

### Drop Hit Event

In this event, we check to see if the target that was dropped on was not an LI node. If it wasn't, then we know it was dropped on the empty space of the UL.

    Y.DD.DDM.on('drag:drophit', function(e) {    var drop = e.drop.get('node'),        drag = e.drag.get('node');     //if we are not on an li, we must have been dropped on a ul    if (drop.get('tagName').toLowerCase() !== 'li') {        if (!drop.contains(drag)) {            drop.appendChild(drag);        }    }});

    Y.DD.DDM.on('drag:drophit', function(e) {
        var drop = e.drop.get('node'),
            drag = e.drag.get('node');

        //if we are not on an li, we must have been dropped on a ul
        if (drop.get('tagName').toLowerCase() !== 'li') {
            if (!drop.contains(drag)) {
                drop.appendChild(drag);
            }
        }
    });

Y.DD.DDM.on('drag:drophit', function(e) { var drop = e.drop.get('node'), drag = e.drag.get('node'); //if we are not on an li, we must have been dropped on a ul if (drop.get('tagName').toLowerCase() !== 'li') { if (!drop.contains(drag)) { drop.appendChild(drag); } } });

### Full Javascript Source

    YUI().use('dd-constrain', 'dd-proxy', 'dd-drop', function(Y) {    //Listen for all drop:over events    Y.DD.DDM.on('drop:over', function(e) {        //Get a reference to out drag and drop nodes        var drag = e.drag.get('node'),            drop = e.drop.get('node');         //Are we dropping on a li node?        if (drop.get('tagName').toLowerCase() === 'li') {            //Are we not going up?            if (!goingUp) {                drop = drop.get('nextSibling');            }            //Add the node to this list            e.drop.get('node').get('parentNode').insertBefore(drag, drop);            //Resize this nodes shim, so we can drop on it later.            e.drop.sizeShim();        }    });    //Listen for all drag:drag events    Y.DD.DDM.on('drag:drag', function(e) {        //Get the last y point        var y = e.target.lastXY[1];        //is it greater than the lastY var?        if (y < lastY) {            //We are going up            goingUp = true;        } else {            //We are going down..            goingUp = false;        }        //Cache for next check        lastY = y;    });    //Listen for all drag:start events    Y.DD.DDM.on('drag:start', function(e) {        //Get our drag object        var drag = e.target;        //Set some styles here        drag.get('node').setStyle('opacity', '.25');        drag.get('dragNode').set('innerHTML', drag.get('node').get('innerHTML'));        drag.get('dragNode').setStyles({            opacity: '.5',            borderColor: drag.get('node').getStyle('borderColor'),            backgroundColor: drag.get('node').getStyle('backgroundColor')        });    });    //Listen for a drag:end events    Y.DD.DDM.on('drag:end', function(e) {        var drag = e.target;        //Put out styles back        drag.get('node').setStyles({            visibility: '',            opacity: '1'        });    });    //Listen for all drag:drophit events    Y.DD.DDM.on('drag:drophit', function(e) {        var drop = e.drop.get('node'),            drag = e.drag.get('node');         //if we are not on an li, we must have been dropped on a ul        if (drop.get('tagName').toLowerCase() !== 'li') {            if (!drop.contains(drag)) {                drop.appendChild(drag);            }        }    });     //Static Vars    var goingUp = false, lastY = 0;     //Get the list of li's in the lists and make them draggable    var lis = Y.Node.all('#play ul li');    lis.each(function(v, k) {        var dd = new Y.DD.Drag({            node: v,            target: {                padding: '0 0 0 20'            }        }).plug(Y.Plugin.DDProxy, {            moveOnEnd: false        }).plug(Y.Plugin.DDConstrained, {            constrain2node: '#play'        });    });     //Create simple targets for the 2 lists..    var uls = Y.Node.all('#play ul');    uls.each(function(v, k) {        var tar = new Y.DD.Drop({            node: v        });    }); });

    YUI().use('dd-constrain', 'dd-proxy', 'dd-drop', function(Y) {
        //Listen for all drop:over events
        Y.DD.DDM.on('drop:over', function(e) {
            //Get a reference to out drag and drop nodes
            var drag = e.drag.get('node'),
                drop = e.drop.get('node');

            //Are we dropping on a li node?
            if (drop.get('tagName').toLowerCase() === 'li') {
                //Are we not going up?
                if (!goingUp) {
                    drop = drop.get('nextSibling');
                }
                //Add the node to this list
                e.drop.get('node').get('parentNode').insertBefore(drag, drop);
                //Resize this nodes shim, so we can drop on it later.
                e.drop.sizeShim();
            }
        });
        //Listen for all drag:drag events
        Y.DD.DDM.on('drag:drag', function(e) {
            //Get the last y point
            var y = e.target.lastXY[1];
            //is it greater than the lastY var?
            if (y < lastY) {
                //We are going up
                goingUp = true;
            } else {
                //We are going down..
                goingUp = false;
            }
            //Cache for next check
            lastY = y;
        });
        //Listen for all drag:start events
        Y.DD.DDM.on('drag:start', function(e) {
            //Get our drag object
            var drag = e.target;
            //Set some styles here
            drag.get('node').setStyle('opacity', '.25');
            drag.get('dragNode').set('innerHTML', drag.get('node').get('innerHTML'));
            drag.get('dragNode').setStyles({
                opacity: '.5',
                borderColor: drag.get('node').getStyle('borderColor'),
                backgroundColor: drag.get('node').getStyle('backgroundColor')
            });
        });
        //Listen for a drag:end events
        Y.DD.DDM.on('drag:end', function(e) {
            var drag = e.target;
            //Put out styles back
            drag.get('node').setStyles({
                visibility: '',
                opacity: '1'
            });
        });
        //Listen for all drag:drophit events
        Y.DD.DDM.on('drag:drophit', function(e) {
            var drop = e.drop.get('node'),
                drag = e.drag.get('node');

            //if we are not on an li, we must have been dropped on a ul
            if (drop.get('tagName').toLowerCase() !== 'li') {
                if (!drop.contains(drag)) {
                    drop.appendChild(drag);
                }
            }
        });

        //Static Vars
        var goingUp = false, lastY = 0;

        //Get the list of li's in the lists and make them draggable
        var lis = Y.Node.all('#play ul li');
        lis.each(function(v, k) {
            var dd = new Y.DD.Drag({
                node: v,
                target: {
                    padding: '0 0 0 20'
                }
            }).plug(Y.Plugin.DDProxy, {
                moveOnEnd: false
            }).plug(Y.Plugin.DDConstrained, {
                constrain2node: '#play'
            });
        });

        //Create simple targets for the 2 lists..
        var uls = Y.Node.all('#play ul');
        uls.each(function(v, k) {
            var tar = new Y.DD.Drop({
                node: v
            });
        });

    });

YUI().use('dd-constrain', 'dd-proxy', 'dd-drop', function(Y) { //Listen for all drop:over events Y.DD.DDM.on('drop:over', function(e) { //Get a reference to out drag and drop nodes var drag = e.drag.get('node'), drop = e.drop.get('node'); //Are we dropping on a li node? if (drop.get('tagName').toLowerCase() === 'li') { //Are we not going up? if (!goingUp) { drop = drop.get('nextSibling'); } //Add the node to this list e.drop.get('node').get('parentNode').insertBefore(drag, drop); //Resize this nodes shim, so we can drop on it later. e.drop.sizeShim(); } }); //Listen for all drag:drag events Y.DD.DDM.on('drag:drag', function(e) { //Get the last y point var y = e.target.lastXY[1]; //is it greater than the lastY var? if (y < lastY) { //We are going up goingUp = true; } else { //We are going down.. goingUp = false; } //Cache for next check lastY = y; }); //Listen for all drag:start events Y.DD.DDM.on('drag:start', function(e) { //Get our drag object var drag = e.target; //Set some styles here drag.get('node').setStyle('opacity', '.25'); drag.get('dragNode').set('innerHTML', drag.get('node').get('innerHTML')); drag.get('dragNode').setStyles({ opacity: '.5', borderColor: drag.get('node').getStyle('borderColor'), backgroundColor: drag.get('node').getStyle('backgroundColor') }); }); //Listen for a drag:end events Y.DD.DDM.on('drag:end', function(e) { var drag = e.target; //Put out styles back drag.get('node').setStyles({ visibility: '', opacity: '1' }); }); //Listen for all drag:drophit events Y.DD.DDM.on('drag:drophit', function(e) { var drop = e.drop.get('node'), drag = e.drag.get('node'); //if we are not on an li, we must have been dropped on a ul if (drop.get('tagName').toLowerCase() !== 'li') { if (!drop.contains(drag)) { drop.appendChild(drag); } } }); //Static Vars var goingUp = false, lastY = 0; //Get the list of li's in the lists and make them draggable var lis = Y.Node.all('#play ul li'); lis.each(function(v, k) { var dd = new Y.DD.Drag({ node: v, target: { padding: '0 0 0 20' } }).plug(Y.Plugin.DDProxy, { moveOnEnd: false }).plug(Y.Plugin.DDConstrained, { constrain2node: '#play' }); }); //Create simple targets for the 2 lists.. var uls = Y.Node.all('#play ul'); uls.each(function(v, k) { var tar = new Y.DD.Drop({ node: v }); }); });

Copyright © 2009 Yahoo! Inc. All rights reserved.

Privacy Policy - Terms of Service - Copyright Policy - Job Openings