Jump to Table of Contents

Example: Fish Sort - Multi Outer Join

This example has 2 sortable lists, each with floated nodes. The lists are outer joined together. The small fish on the left can move into the groups on the right, and become sortable (and larger). However, the items in the groups on the right cannot move back into the list of small fish.

  • Fish:Round, 2 stripes
    Cat. #34620
  • Fish:Spiked dorsal, dark
    Cat. #31899
  • Fish:Long comb dorsal
    Cat. #32230
  • Fish:Sole, medium
    Cat. #32003
  • Fish:Round, 3 stripes
    Cat. #34551
  • Fish:Sole, light
    Cat. #32398
  • Fish:Lots of spiked fins
    Cat. #36667
  • Fish:Round, 4 stripes
    Cat. #34821
  • Fish:Big Spiked dorsal, light
    Cat. #38144
  • Fish:Long comb dorsal
    Cat. #32445
  • Fish:Sole, dark
    Cat. #32201
  • Fish:Long comb dorsal, pointy
    Cat. #32011
  • Group A
  • Fish:Round, 5 stripes
    Cat. #34114
  • Group B
  • Group C
  • Group D

Images of fish etchings are from Jacob Theodor Klein, mid 1700s. Source: http://www.flickr.com/photos/biodivlibrary/sets/72157627937663760/. Contributed by: MBLWHOI Library, Woods Hole.

Note: When using an outer or inner joined list, you must pick a moveType of 'move' or 'copy', the default 'swap' won't give you the results you expect.

This example assumes that you have seen the Multiple Sortable Lists - Full Join example and continues from there.

Setting Up the List

First we need to create the HTML structure for the lists. Since Sortable uses Y.DD.Delegate, we need to set up the delegation containers (#list1, #lists2) and the list items (li).

<div id="demo" class="yui-g">
    <div id="col-left" class="yui3-u">
        <ul id="list1">
            <li class="fish"><img src="../assets/sortable/images/efish_03.png" alt="Fish:Round, 2 stripes"/><div class="cat-num">Cat. #34620</div></li>
            <li class="fish"><img src="../assets/sortable/images/efish_09.png" alt="Fish:Spiked dorsal, dark"/><div class="cat-num">Cat. #31899</div></li>
            <li class="fish"><img src="../assets/sortable/images/efish_12.png" alt="Fish:Long comb dorsal"/><div class="cat-num">Cat. #32230</div></li>
            <li class="fish"><img src="../assets/sortable/images/efish_05.png" alt="Fish:Sole, medium"/><div class="cat-num">Cat. #32003</div></li>
            <li class="fish"><img src="../assets/sortable/images/efish_04.png" alt="Fish:Round, 3 stripes"/><div class="cat-num">Cat. #34551</div></li>
            <li class="fish"><img src="../assets/sortable/images/efish_06.png" alt="Fish:Sole, light"/><div class="cat-num">Cat. #32398</div></li>
            <li class="fish"><img src="../assets/sortable/images/efish_08.png" alt="Fish:Lots of spiked fins"/><div class="cat-num">Cat. #36667</div></li>
            <li class="fish"><img src="../assets/sortable/images/efish_02.png" alt="Fish:Round, 4 stripes"/><div class="cat-num">Cat. #34821</div></li>
            <li class="fish"><img src="../assets/sortable/images/efish_10.png" alt="Fish:Big Spiked dorsal, light"/><div class="cat-num">Cat. #38144</div></li>
            <li class="fish"><img src="../assets/sortable/images/efish_13.png" alt="Fish:Long comb dorsal"/><div class="cat-num">Cat. #32445</div></li>
            <li class="fish"><img src="../assets/sortable/images/efish_07.png" alt="Fish:Sole, dark"/><div class="cat-num">Cat. #32201</div></li>
            <li class="fish"><img src="../assets/sortable/images/efish_11.png" alt="Fish:Long comb dorsal, pointy"/><div class="cat-num">Cat. #32011</div></li>
        </ul>
    </div>
    <div id="col-right" class="yui3-u">
        <ul id="list2">
            <li class="group-hd">Group A</li>
            <!-- This fish has already been pre-placed in a group -->
            <li class="fish"><img src="../assets/sortable/images/efish_01.png" alt="Fish:Round, 5 stripes"/><div class="cat-num">Cat. #34114</div></li>
            <li class="group-hd">Group B</li>
            <li class="group-hd">Group C</li>
            <li class="group-hd">Group D</li>
        </ul>
    </div>
</div>

Now we give the lists some CSS to make them visible.

.example {
    background-color: #DCCFBB;
    font-family: georgia;
    /* a repeating grid image in the background */
    background-image: url(../assets/sortable/images/grid.png);
}
#demo {
    float: none;
    border: solid 1px #C8B9A4;
    width: 655px;
    margin: auto;
    -moz-border-radius: 3px;
    -webkit-border-radius: 3px;
    border-radius: 3px;
}
#demo #col-left{ 
    width: 231px;
}    
#demo #col-right {
    width: 417px;
    padding-bottom: 2em; /* needs bottom padding so objects can drag below last .group-hd */    
    border-left: solid 1px #C8B9A4;
}
#demo ul{
    margin: 0;
    padding: 0;
    list-style-type: none;
}
#demo #list1 li,
#demo #list2 li{ 
    float: left; /* the li objects are floated */
    margin: 3px;
    background-color: #E9CE98; 
}
#demo #list1 li{
    height: 56px;
    width: 68px;
    overflow: hidden; /* this hides the catalog number on the small fish */
}
/* the width and height of the .fish items are larger in #list2 */
#demo #list2 .fish{ 
    width: 130px;
    height: 115px; /* The .fish items are taller when on the right to show the catalog number */ 
    text-align: center;
}
/* catalog number style */
#demo #list2 .cat-num{
    font-size: 80%;
    margin: -0.2em 0.5em;
    font-style: italic;
    color: #9F8A6C;
    height: 1.3em;
    line-height: 0.9em;
}
/* group heads are sortable like other objects but have different style */
#demo #list2 .group-hd{
    background-color: #6F6452; 
    border-color: #EBD6B3 #63532E #63532E #EBD6B3;
    width: 406px;
    height: 20px;
    text-indent: 0.5em;
    font-weight: bold;
    color: #B0986A;
    line-height: 20px;
}
#demo li img{
    width: 100%; /* image scales with size of it's li container */
}
#demo li {
    border: solid 1px;
    -moz-border-radius: 4px;
    -webkit-border-radius: 4px;
    border-radius: 4px;
    border-color: #FFEFC2 #9D8F70 #9D8F70 #FFEFC2;
    -moz-box-shadow: 3px 4px 8px rgba(0, 0, 0, 0.25);
    -webkit-box-shadow: 3px 4px 8px rgba(0, 0, 0, 0.25);
    box-shadow: 3px 4px 8px rgba(0, 0, 0, 0.25);
}

Setting Up the YUI Instance

Now we need to create our YUI instance and tell it to load the sortable module.

In this example we are also going to attach a DD plugin to the Sortable instances.

YUI().use('dd-constrain', 'sortable', function (Y) {
    // Code here.
});

Making the Lists Draggable

Now that we have a YUI instance with the sortable module, we need to instantiate a Sortable instance on each of the lists.

YUI().use('dd-constrain', 'sortable', function(Y) {
    var list1 = new Y.Sortable({
        container: '#list1',
        nodes: 'li',
        opacity: '.1'
    });

    var list2 = new Y.Sortable({
        container: '#list2',
        nodes: 'li',
        opacity: '.1'
    });

});

Applying a DD Plugin

Since Sortable uses DD.Delegate, there is a dd instance available after instantiation.

The DD.Delegate reference is found on the .delegate property of the Sortable. This DD.Delegate instance has a DD.Drag instance bound to the dd property on the DD.Delegate

list1.delegate.dd.plug(Y.Plugin.DDConstrained, {
    constrain2node: '#demo'
});
list2.delegate.dd.plug(Y.Plugin.DDConstrained, {
    constrain2node: '#demo'
});

Applying the Plugin.DDConstrained to the Sortable instance.

YUI().use('dd-constrain', 'sortable', function(Y) {
    var list1 = new Y.Sortable({
        container: '#list1',
        nodes: 'li',
        opacity: '.1'
    });

    var list2 = new Y.Sortable({
        container: '#list2',
        nodes: 'li',
        opacity: '.1'
    });

    list1.delegate.dd.plug(Y.Plugin.DDConstrained, {
        constrain2node: '#demo'
    });
    list2.delegate.dd.plug(Y.Plugin.DDConstrained, {
        constrain2node: '#demo'
    });

});

Joining the Lists

Joining the lists is as simple as calling the join method on one list passing in another list. By default, we use a full join which joins both lists both ways.

You can optionally specify the join type: inner or outer. The moveType can also be specified on the list: swap, move or copy. swap is the default, as seen in this example.

list1.join(list2);              //Full join <-- both ways -->
list1.join(list2, 'outer');     //Outer join --> one way -->
list1.join(list2, 'inner');     //Inner join <-- one way <--

Putting it together

YUI().use('dd-constrain', 'sortable', function(Y) {
    var list1 = new Y.Sortable({
        container: '#list1',
        nodes: 'li',
        opacity: '.1'
    });

    var list2 = new Y.Sortable({
        container: '#list2',
        nodes: 'li',
        opacity: '.1'
    });

    list1.join(list2, 'outer');
});