CHAPTER 24

image

Using the Drag-and-Drop Interactions

In addition to the widgets I showed you in Chapters 1823, jQuery UI includes a set of interactions. These are lower-level building blocks that allow you to add functionality to your web application interface. In this chapter, I describe the draggable and droppable interactions, which you can use to add drag and drop to an HTML document.

The interactions follow the same basic structure as the widgets. They have settings, methods, and events. I will follow the same pattern in describing the interactions, but I’ll be jumping around a little to accommodate the unique nature of some of the interactions.

It is hard to show the effect of applying the interactions using screenshots. They are, as the name suggests, dependent on interaction. I tried to give you the essence of what is happening, but to truly understand interactions you should experiment with them in the browser. All of the examples in this chapter (and every other chapter for that matter) are included in the free Source Code/Download area of the Apress web site (www.apress.com). Table 24-1 provides the summary for this chapter.

Table 24-1. Chapter Summary

Problem Solution Listing
Apply the draggable interaction Use the draggable method 1
Constrain the direction in which an element can be dragged Use the axis setting 2
Limit the area in which the element can be dragged Use the containment setting 3
Constrain dragging to the cells in a grid Use the grid setting 4
Delay dragging for a period of time or for a number of pixels Use the delay and distance settings 5
Respond to an element being dragged Use the start, drag, and stop events 6
Apply the droppable interaction Use the droppable method 7
Highlight a droppable element when an element is being dragged Use the activate and deactivate events 8
Respond when a draggable element overlaps with a droppable element Use the over and out events 9
Specify which draggable elements a droppable element will accept Use the accept setting 10
Automatically apply CSS classes to a droppable element when dragging starts or overlaps Use the activeClass and hoverClass settings 11
Changing the amount of overlap that will trigger the over event Use the tolerance setting 12
Create groups of compatible draggable and droppable elements Use the scope setting 13
Leave the draggable element in place during and after dragging Use the helper setting 14, 15
Manipulate the helper element in response to a droppable event Use the ui.helper property 16
Force the draggable element to snap to the edge of other elements Use the snap, snapMode, and snapTolerance settings 17

Creating the Draggable Interaction

An element to which you apply the draggable interaction can be moved (dragged) around the browser window. The element appears in the initial document layout as it would normally, but the element’s position changes if the user holds down the pointer over the draggable element and moves the mouse. Listing 24-1 provides a demonstration of the draggable interaction.

Listing 24-1.  Using the Draggable Interaction

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <script src="jquery-2.0.2.js" type="text/javascript"></script>
    <script src="jquery-ui-1.10.3.custom.js" type="text/javascript"></script>
    <link rel="stylesheet" type="text/css" href="styles.css"/>
    <link rel="stylesheet" type="text/css" href="jquery-ui-1.10.3.custom.css"/>
    <style type="text/css">
        #draggable {font-size: x-large; border: thin solid black;
            width: 5em; text-align: center}
    </style>
    <script type="text/javascript">
        $(document).ready(function() {
            $("#draggable").draggable();
        });
    </script>
</head>
<body>
    <h1>Jacqui's Flower Shop</h1>
    <div id="draggable">
        Drag me
    </div>
</body>
</html>

In Listing 24-1, I selected a div element and called the draggable method to create a draggable element. As Figure 24-1 shows, the element starts in its regular position but can be dragged anywhere in the browser window. Note that the other element in the document, the h1, is not affected by the draggable method.

9781430263883_Fig24-01.jpg

Figure 24-1. Dragging an element around the browser window

image Tip  Being able to drag elements can be useful in its own right, but it becomes much more powerful when combined with the droppable interaction, which I describe in later in this chapter.

The draggable interaction is performed using some clever HTML and CSS. This means that it works in almost any browser—but it also means draggable elements are not able to interact with the native drag and drop implemented by the user’s operating system.

image Tip  HTML5 includes support for drag and drop that is usually implemented using the native operating system mechanisms. I provide details and examples of HTML5 drag and drop in my book The Definitive Guide to HTML5, also published by Apress. If you are using the jQuery UI drag-and-drop mechanism, I recommend disabling the HTML5 equivalent to avoid confusion. To do this, set the draggable attribute to false on the body element in your document.

Configuring the Draggable Interaction

There are lots of ways you can configure the draggable interaction. Table 24-2 summarizes the most important settings available, which I demonstrate in the sections that follow.

Table 24-2. Draggable Settings

Setting Description
axis Restricts the drag to a particular direction. The default is false, meaning no restriction, but you can also specify x (for the x-axis) and y (for the y-axis).
containment Restricts the draggable element to a region of the screen. See Table 24-3 for details of the supported range of values. The default is false, meaning no restriction.
delay Specifies a duration for which the user must drag the element before it moves. The default is 0, meaning no delay.
distance Specifies a distance that the user must drag the element from its initial position before it moves. The default is 1 pixel.
grid Forces the draggable element to snap to a grid. The default is false, meaning no grid will be used.

image Tip  In the Tuning Drag & Drop section later in the chapter, I describe some additional settings that change the relationship between the draggable and droppable elements.

Constraining the Drag Axis

There are several ways in which you can constrain the way an element can be dragged. The first is to use the axis setting, which allows you to limit dragging to the x-axis or y-axis. Listing 24-2 provides an example.

Listing 24-2.  Using the axis Setting to Constrain Dragging

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <script src="jquery-2.0.2.js" type="text/javascript"></script>
    <script src="jquery-ui-1.10.3.custom.js" type="text/javascript"></script>
    <link rel="stylesheet" type="text/css" href="styles.css"/>
    <link rel="stylesheet" type="text/css" href="jquery-ui-1.10.3.custom.css"/>
    <style type="text/css">
        div.dragElement {font-size: large; border: thin solid black;
            width: 5em; text-align: center; background-color: lightgray; margin: 4px }
    </style>
    <script type="text/javascript">
        $(document).ready(function() {
              
            $(".dragElement").draggable({
                axis: "x"
            }).filter("#dragV").draggable("option", "axis", "y");
              
        });
    </script>
</head>
<body>
    <h1>Jacqui's Flower Shop</h1>
    <div id="dragV" class="dragElement">
        Drag Vertically
    </div>
    <div id="dragH" class="dragElement">
        Drag Horizontally
    </div>
</body>
</html>

In Listing 24-2, I defined two div elements, selected them with jQuery, and called the draggable method. I use the settings object to define a value of x for both div elements initially, and then use the jQuery filter method to select the dragV element so that I can change the y setting without having to make jQuery search the entire document again. The result is one div element that can be dragged vertically and another that can be dragged horizontally. You can see the effect in Figure 24-2.

9781430263883_Fig24-02.jpg

Figure 24-2. Constraining the direction in which an element can be dragged

Constraining the Drag Region

You can limit the region of the screen in which an element can be dragged. You do this through the containment setting. This setting can be set using several formats, as described in Table 24-3.

Table 24-3. Values for the Containment Setting

Value Description
Selector When you specify a selector string, the draggable element is constrained to the area occupied by the first matching element
HTMLElement The draggable element is constrained to the area occupied by the specified element
string You can specify the values parent, document, and window to restrict dragging
Number Array You can use a number array in the format [x1, y1, x2, y2] to restrict dragging to a region

Listing 24-3 shows the use of the containment setting.

Listing 24-3.  Using the containment Setting

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <script src="jquery-2.0.2.js" type="text/javascript"></script>
    <script src="jquery-ui-1.10.3.custom.js" type="text/javascript"></script>
    <link rel="stylesheet" type="text/css" href="styles.css"/>
    <link rel="stylesheet" type="text/css" href="jquery-ui-1.10.3.custom.css"/>
    <style type="text/css">
        div.dragElement {font-size: large; border: thin solid black; padding: 4px;
            width: 5em; text-align: center; background-color: lightgray; margin: 4px }
        #container { border: medium double black; width: 400px; height: 150px}
    </style>
    <script type="text/javascript">
        $(document).ready(function() {
            $(".dragElement").draggable({
                containment: "parent"
            }).filter("#dragH").draggable("option", "axis", "x");
              
        });
    </script>
</head>
<body>
    <h1>Jacqui's Flower Shop</h1>
    <div id="container">
        <div id="dragH" class="dragElement">
            Drag Horizontally
        </div>
        <div class="dragElement">
            Drag within Parent
        </div>
    </div>
</body>
</html>

In Listing 24-3, I constrained both div elements such that they can be dragged only within their parent element, which is a fixed-size div element. For one of the draggable div elements, I also applied the axis setting, meaning that it can be dragged only horizontally within the parent element. You can see the result in Figure 24-3.

9781430263883_Fig24-03.jpg

Figure 24-3. Restricting dragging to the parent element

Constraining Dragging to a Grid

The grid setting can be used to make a draggable element snap to a grid as it is dragged. The value for this setting is a two-element array specifying the width and the height of the grid in pixels. Listing 24-4 shows the grid setting in use.

Listing 24-4.  Using the Grid Setting

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <script src="jquery-2.0.2.js" type="text/javascript"></script>
    <script src="jquery-ui-1.10.3.custom.js" type="text/javascript"></script>
    <link rel="stylesheet" type="text/css" href="styles.css"/>
    <link rel="stylesheet" type="text/css" href="jquery-ui-1.10.3.custom.css"/>
    <style type="text/css">
        #draggable {font-size: large; border: thin solid black; padding: 4px;
            width: 100px; text-align: center; background-color: lightgray; margin: 4px; }
    </style>
    <script type="text/javascript">
        $(document).ready(function() {
            $("#draggable").draggable({
                grid: [100, 50]
            })
        });
    </script>
</head>
<body>
    <h1>Jacqui's Flower Shop</h1>
    <div id="draggable">
        Drag Me
    </div>
</body>
</html>

In Listing 24-4, I specified a grid in which the cells are 100 pixels wide and 50 pixels high. As you drag the element, it snaps from one (invisible) cell to the next, as shown in Figure 24-4.

9781430263883_Fig24-04.jpg

Figure 24-4. Dragging an element with a grid

The snapping effect is hard to represent in a screenshot and this is an example that particularly benefits from interaction.

image Tip  You can snap-to-grid in one direction only by specifying a value of 1 for the free-movement axis. For example, setting a value of [100, 1] forces the draggable element to snap to 100 pixel cells along the x-axis but allows free movement along the y-axis.

Delaying Dragging

There are two settings that allow you to delay the dragging action. You can use the delay setting to specify a time span so that the user has to drag the element for a number of milliseconds before the element starts to move. You can also use the distance setting, which forces the user make the drag motion for a certain number of pixels before the element begins to follow the mouse. Listing 24-5 shows both settings in use.

Listing 24-5.  Using the delay and distance Settings

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <script src="jquery-2.0.2.js" type="text/javascript"></script>
    <script src="jquery-ui-1.10.3.custom.js" type="text/javascript"></script>
    <link rel="stylesheet" type="text/css" href="styles.css"/>
    <link rel="stylesheet" type="text/css" href="jquery-ui-1.10.3.custom.css"/>
    <style type="text/css">
        #time, #distance {font-size: large; border: thin solid black; padding: 4px;
            width: 100px; text-align: center; background-color: lightgray; margin: 4px; }
    </style>
    <script type="text/javascript">
        $(document).ready(function() {
            $("#time").draggable({
                delay: 1000
            })
              
            $("#distance").draggable({
                distance: 150
            })
        });
    </script>
</head>
<body>
    <h1>Jacqui's Flower Shop</h1>
    <div id="time">Time Delay</div>
    <div id="distance">Distance</div>
</body>
</html>

I have two draggable div elements in Listing 24-5, one of which I configured with the delay setting and the other with the distance setting. When using the delay, the user has to continue dragging for the specified number of milliseconds before the element will begin to move. This is 1,000 milliseconds in the example. The user doesn’t have to keep the mouse moving for this duration, but the mouse button has to be held down for the entire period and the mouse has to have been moved to start the dragging process. When the time span has elapsed, the draggable element will snap to the location of the mouse pointer, subject to the grid, region, and axis constraints I showed you earlier.

The distance setting has a similar effect, but the user has to have moved the mouse pointer at least the specified number of pixels in any direction from the element’s starting point. When the mouse has moved that far, the draggable element will snap to the current mouse location.

image Tip  If you apply both settings to a single element, the draggable element won’t move until both conditions have been met—that is, the user has to have been dragging for the specified time span and moved the mouse the specified number of pixels.

Using the Draggable Methods

The draggable interaction defines only the set of core methods you saw implemented by the widgets. There are no draggable-specific methods. Table 24-4 describes those that are available.

Table 24-4. Draggable Methods

Method Description
draggable("destroy") Removes the interaction from the element
draggable("disable") Disables the draggable interaction
draggable("enable") Enables the draggable interaction
draggable("option") Changes one or more settings

Using the Draggable Events

The draggable interaction supports a simple set of events that notify you when an element is dragged. Table 24-5 describes the events.

Table 24-5. Draggable Events

Event Description
create Triggered when the draggable interaction is applied to an element
start Triggered when dragging starts
drag Triggered as the mouse moves during dragging
stop Triggered when dragging stops

You respond to interaction events just as you do for widget events. Listing 24-6 demonstrates handling the start and stop events.

Listing 24-6.  Using the Draggable start and stop Events

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <script src="jquery-2.0.2.js" type="text/javascript"></script>
    <script src="jquery-ui-1.10.3.custom.js" type="text/javascript"></script>
    <link rel="stylesheet" type="text/css" href="styles.css"/>
    <link rel="stylesheet" type="text/css" href="jquery-ui-1.10.3.custom.css"/>
    <style type="text/css">
        #draggable {font-size: large; border: thin solid black; padding: 4px;
            width: 100px; text-align: center; background-color: lightgray; margin: 4px; }
    </style>
    <script type="text/javascript">
        $(document).ready(function() {
            $("#draggable").draggable({
                start: function() {
                    $("#draggable").text("Dragging...")
                },
                stop: function() {
                    $("#draggable").text("Drag Me")
                }
            })
        });
    </script>
</head>
<body>
    <h1>Jacqui's Flower Shop</h1>
    <div id="draggable">
        Drag Me
    </div>
</body>
</html>

In Listing 24-6, I use the start and stop events to change the contents of the element while it is being dragged. This is a benefit of the way that the draggable interaction (and all of the other jQuery UI interactions, for that matter) is implemented using HTML and CSS: you can use jQuery to modify the draggable element even when it is being moved around the screen. You can see the effect that this example creates in Figure 24-5.

9781430263883_Fig24-05.jpg

Figure 24-5. Using the draggable events to modify an element while it is being dragged

Using the Droppable Interaction

The real utility of the draggable interaction arises when you combine it with the droppable interaction. You create droppable elements using the droppable method, but to get any real functionality you need to provide handler functions for the events that the interaction defines. Table 24-6 describes the events that are available.

Table 24-6. Droppable Events

Event Description
create Triggered when the droppable interaction is applied
activate Triggered when the user starts to drag a draggable element
deactivate Triggered when the user stops dragging a draggable element
over Triggered when the user drags a draggable element over the droppable element (but has not yet released the mouse button)
out Triggered when the user drags a draggable element out of the droppable element
drop Triggered when the user drops a draggable element on the droppable element

You can create a basic droppable element with just the drop event, as shown in Listing 24-7.

Listing 24-7.  Creating a Basic Droppable Interaction

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <script src="jquery-2.0.2.js" type="text/javascript"></script>
    <script src="jquery-ui-1.10.3.custom.js" type="text/javascript"></script>
    <link rel="stylesheet" type="text/css" href="styles.css"/>
    <link rel="stylesheet" type="text/css" href="jquery-ui-1.10.3.custom.css"/>
    <style type="text/css">
        #draggable, #droppable {font-size: large; border: thin solid black; padding: 4px;
            width: 100px; text-align: center; background-color: lightgray; margin: 4px;}
        #droppable {padding: 20px; position: absolute; left: 5px; bottom: 5px}
    </style>
    <script type="text/javascript">
        $(document).ready(function() {
            $("#draggable").draggable();
              
            $("#droppable").droppable({
                drop: function() {
                    $("#draggable").text("Dropped")
                }
            });
        });
    </script>
</head>
<body>
    <h1>Jacqui's Flower Shop</h1>
    <div id="droppable">
        Drop Here
    </div>
    <div id="draggable">
        Drag Me
    </div>
</body>
</html>

I added a div element whose text content is Drop Here. I use jQuery to select this element and call the droppable method, passing in a settings object that defines a handler for the drop event. In response to this method, I change the text of the draggable element using the text method. Listing 24-7 creates the dullest possible drag-and-drop interaction, but it also provides a useful foundation to explain the way that the draggable and droppable interactions can be used together. You can see the different stages of the example in Figure 24-6.

9781430263883_Fig24-06.jpg

Figure 24-6. Using simple drag and drop

This is pretty basic stuff. I drag the draggable element over the droppable element and let go. The draggable element stays where I left it, and its text content is changed in response to the drop event. In the sections that follow, I’ll show you how to use the other droppable events to improve the experience.

Highlighting a Drop Target

You can use the activate and deactivate events to highlight the drop target when the user starts the drag motion. This is usually a good idea, because it gives the user a clear signal regarding which elements are part of the drag-and-drop model. Listing 24-8 provides an example.

Listing 24-8.  Responding to the activate and deactivate Events

...
<script type="text/javascript">
    $(document).ready(function() {
        $("#draggable").draggable();
          
        $("#droppable").droppable({
            drop: function() {
                $("#draggable").text("Dropped");
            },
            activate: function() {
                $("#droppable").css({
                    border: "medium double green",
                    backgroundColor: "lightGreen"
                });
            },
            deactivate: function() {
                $("#droppable").css("border", "").css("background-color", "");
            }
        });
    });
</script>
...

When the user starts dragging an element, my droppable element triggers the activate event and my handler function uses the css method to apply new values for the CSS border and background-color properties. This causes the drop target to light up, indicating to the user that the droppable element has a relationship to the element being dragged. I use the deactivate event to remove the CSS property values and return the droppable element to its original state when the user releases the mouse button. (This event is triggered whenever dragging stops, regardless of whether the user has dropped the draggable element on a droppable element.) You can see the effect in Figure 24-7.

9781430263883_Fig24-07.jpg

Figure 24-7. Using the activate and deactivate events

Dealing with Overlapping Elements

You can refine your drag-and-drop technique by handling the over and out events. The over event is triggered when 50% of a draggable element is over any part of the droppable element. The out event is triggered when the elements no longer overlap. Listing 24-9 shows how you can respond to these events.

Listing 24-9.  Using the over and out Events

...
<script type="text/javascript">
    $(document).ready(function() {
        $("#draggable").draggable();
          
        $("#droppable").droppable({
            drop: function() {
                $("#draggable").text("Dropped");
            },
            over: function() {
                $("#droppable").css({
                    border: "medium double green",
                    backgroundColor: "lightGreen"
                });
            },
            out: function() {
                $("#droppable").css("border", "").css("background-color", "");
            }
        });
    });
</script>
...

I used the same event handler functions as in the previous example, but I associated them with the over and out events. The droppable element will show the border and background color when at least 50% of the draggable element overlaps with it, as shown in Figure 24-8.

9781430263883_Fig24-08.jpg

Figure 24-8. Responding to the over and out events

image Tip  The 50% limit is known as the tolerance, and you can configure the droppable element with different tolerances, as I demonstrate in the section “Changing the Overlap Tolerance.”

Configuring the Droppable Interaction

I broke away from the usual pattern in this part of the book because the events are so central to the droppable interaction. Of course, this interaction does have a number of settings you can use to change the way that it behaves and these are described in Table 24-7.

Table 24-7. Droppable Settings

Setting Description
disabled When true, the interaction is disabled initially. The default is false.
accept Narrows the draggable elements that the droppable element will respond to. The default is *, which matches all elements.
activeClass Specifies a class that will be applied in response to the activate event and removed in response to the deactivate event.
hoverClass Specifies a class that will be applied in response to the over event and removed in response to the out event.
tolerance Specifies the amount of overlap that has to occur before the on event is triggered.

image Tip  In the section “Tuning Drag and Drop,” I describe some additional settings that change the relationship between the draggable and droppable elements.

Restricting Acceptable Draggable Elements

You can restrict the set of elements you are willing to receive with your droppable interaction by applying the accept setting. You use the accept setting by providing a selector as the value. This has the effect of triggering only the droppable events when a draggable element matches the selector. Listing 24-10 provides an example.

Listing 24-10.  Restricting the Acceptable Elements

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <script src="jquery-2.0.2.js" type="text/javascript"></script>
    <script src="jquery-ui-1.10.3.custom.js" type="text/javascript"></script>
    <link rel="stylesheet" type="text/css" href="styles.css"/>
    <link rel="stylesheet" type="text/css" href="jquery-ui-1.10.3.custom.css"/>
    <style type="text/css">
        .draggable, #droppable {font-size: large; border: thin solid black; padding: 4px;
            width: 100px; text-align: center; background-color: lightgray; margin: 4px;}
        #droppable {padding: 20px; position: absolute; left: 5px; bottom: 5px}
    </style>
    <script type="text/javascript">
        $(document).ready(function() {
            $(".draggable").draggable();
              
            $("#droppable").droppable({
                drop: function(event, ui) {
                    ui.draggable.text("Dropped");
                },
                activate: function() {
                    $("#droppable").css({
                        border: "medium double green",
                        backgroundColor: "lightGreen"
                    });
                },
                deactivate : function() {
                    $("#droppable").css("border", "").css("background-color", "");
                },
                accept: "#drag1"
            });
        });
    </script>
</head>
<body>
    <h1>Jacqui's Flower Shop</h1>
    <div id="droppable">
        Drop Here
    </div>
    <div id="drag1" class="draggable">
        Drag 1
    </div>
    <div id="drag2" class="draggable">
        Drag 2
    </div>
</body>
</html>

There are two draggable elements in this example, with the IDs drag1 and drag2. When creating the droppable element, I used the accept setting to specify that only the drag1 element should be accepted. When the drag1 element is dragged, you see the same effect as in the previous example. The activate, deactivate, over, out, and drop events are all fired at the appropriate moments. However, when you drag the drag2 element, it fails to match the selector I specified for the accept setting and those events don’t fire. I can still drag the element around, but I can no longer drop it on the droppable element. You can see the effect in Figure 24-9.

9781430263883_Fig24-09.jpg

Figure 24-9. Using the accept setting

Notice that I changed the way I select the dropped element so that I can call the text method. When there was only one draggable element in the document, I just used the id attribute, as follows:

...
$("#draggable").text("Dropped");
...

In this example, there are multiple draggable elements, so selecting by id won’t work because I’ll always be changing the text on the same element, regardless of which one was dropped. Instead, I use the ui object, which jQuery UI provides as an additional argument to the event handling functions. The draggable property of the ui object returns a jQuery object that contains the element that the user is dragging or has dropped, allowing me to target that element as follows:

...
ui.draggable.text("Dropped");
...

Highlighting the Droppable Using Classes

You can use the activeClass and hoverClass settings to change the appearance of the droppable element without using the activate, deactivate, over, and out events. Listing 24-11 provides a demonstration.

Listing 24-11.  Using the activeClass and hoverClass Settings

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <script src="jquery-2.0.2.js" type="text/javascript"></script>
    <script src="jquery-ui-1.10.3.custom.js" type="text/javascript"></script>
    <link rel="stylesheet" type="text/css" href="styles.css"/>
    <link rel="stylesheet" type="text/css" href="jquery-ui-1.10.3.custom.css"/>
    <style type="text/css">
        .draggable, #droppable {font-size: large; border: thin solid black; padding: 4px;
            width: 100px; text-align: center; background-color: lightgray; margin: 4px;}
        #droppable {padding: 20px; position: absolute; left: 5px; bottom: 5px}
        #droppable.active {border: thick solid green}
        #droppable.hover {background-color: lightgreen}
    </style>
    <script type="text/javascript">
        $(document).ready(function() {
            $(".draggable").draggable();
              
            $("#droppable").droppable({
                drop: function(event, ui) {
                    ui.draggable.text("Dropped");
                },
                activeClass: "active",
                hoverClass: "hover"
            });
        });
    </script>
</head>
<body>
    <h1>Jacqui's Flower Shop</h1>
    <div id="droppable">
        Drop Here
    </div>
    <div class="draggable">
        Drag Me
    </div>
</body>
</html>

I defined two new CSS styles, which I have highlighted in the listing. I created classes that are specific to the id of the draggable element (e.g., #draggable.active) so that they are more specific than the other styles I have been using (e.g., #droppable) and so that they take precedence. See Chapter 3 for details of the rules by which CSS styles are applied to elements.

Having defined these styles, I then name them as the values to the activeClass and hoverClass settings. The droppable interaction takes care of adding and removing these classes from the droppable elements in response to the events. You can see the result in Figure 24-10.

9781430263883_Fig24-10.jpg

Figure 24-10. Using the activeClass and hoverClass Settings

Changing the Overlap Tolerance

By default, the over event will trigger only when at least 50% of the draggable element overlaps with the droppable element. You can change this using the tolerance setting , which accepts the values shown in Table 24-8.

Table 24-8. Tolerance Values

Value Description
fit The dragged element must completely overlap the droppable element.
intersect At least 50% of the dragged element must overlap the droppable element. This is the default.
pointer The mouse pointer must be over the droppable element, regardless of where the user has grabbed the draggable element.
touch The dragged element must overlap the droppable element by any amount.

The two values I use most frequently are fit and touch, because these represent the most readily understood approaches to the user. I use fit when I preserve the location of the dropped item and touch when I have the dropped item revert to its original location (something I demonstrate later in the chapter). Listing 24-12 shows the use of the fit and touch settings.

Listing 24-12.  Changing the Tolerance for Draggable Elements

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <script src="jquery-2.0.2.js" type="text/javascript"></script>
    <script src="jquery-ui-1.10.3.custom.js" type="text/javascript"></script>
    <link rel="stylesheet" type="text/css" href="styles.css"/>
    <link rel="stylesheet" type="text/css" href="jquery-ui-1.10.3.custom.css"/>
    <style type="text/css">
        .draggable, .droppable {font-size: large; border: thin solid black; padding: 4px;
            width: 100px; text-align: center; background-color: lightgray;}
        .droppable {margin-bottom: 10px; margin-right: 5px; height: 50px; width: 120px}
        #dropContainer {position: absolute; right: 5px;}
        div span {position: relative; top: 25%}
        .droppable.active {border: thick solid green}
        .droppable.hover {background-color: lightgreen}
    </style>
    <script type="text/javascript">
        $(document).ready(function() {
              
            $(".draggable").draggable();
              
            $("div.droppable").droppable({
                drop: function(event, ui) {
                    ui.draggable.text("Dropped");
                },
                activeClass: "active",
                hoverClass: "hover",
                tolerance: "fit"
            });
              
            $("#touchDrop").droppable("option", "tolerance", "touch");
        });
    </script>
</head>
<body>
    <h1>Jacqui's Flower Shop</h1>
    <div id="dropContainer">
        <div id="fitDrop" class="droppable">
            <span>Fit</span>
        </div>
        <div id="touchDrop" class="droppable">
            <span>Touch</span>
        </div>
    </div>
    <div class="draggable">
        <span>Drag Me</span>
    </div>
</body>
</html>

In Listing 24-12, I created two droppable elements, one of which is configured with the fit value for the tolerance setting and the other with the touch value. There is a single draggable element, and Figure 24-11 shows the effect that the different values create. I took each screenshot at the moment that the over event triggered. Notice that the border I applied to the droppable elements is included when the tolerance setting is used to determine overlap.

9781430263883_Fig24-11.jpg

Figure 24-11. Using the fit and touch values for the tolerance setting

Using the Droppable Methods

The droppable interaction defines only the set of core methods you saw implemented by the widgets. There are no interaction-specific methods. Table 24-9 describes those that are available.

Table 24-9. Droppable Methods

Method Description
droppable("destroy") Removes the interaction from the element
droppable("disable") Disables the droppable interaction
droppable("enable") Enables the droppable interaction
droppable("option") Changes one or more settings

Tuning Drag and Drop

There are some additional settings you can use to fine-tune the way jQuery UI drag and drop works. In this section, I describe the settings and demonstrate their use.

Using Element Scope

Earlier in the chapter, I showed how the droppable accept setting can be used to filter the elements that will activate the drop zone. Using selectors works just fine for simple projects, but the selectors can become overly complex and error prone if you have a lot of draggable elements to manage.

An alternative is to apply the scope setting on both the draggable and droppable elements. A draggable element will activate droppable elements with the same scope value. Listing 24-13 shows the scope setting in use.

image Tip  The scope setting can be combined with the accept setting in droppable elements. The droppable element will be activated only if the draggable element shares the same scope and matches the selector defined by the accept setting.

Listing 24-13.  Using the scope Setting

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <script src="jquery-2.0.2.js" type="text/javascript"></script>
    <script src="jquery-ui-1.10.3.custom.js" type="text/javascript"></script>
    <link rel="stylesheet" type="text/css" href="styles.css"/>
    <link rel="stylesheet" type="text/css" href="jquery-ui-1.10.3.custom.css"/>
    <style type="text/css">
        .draggable, .droppable {font-size: large; border: medium solid black;
            padding: 4px; width: 100px; text-align: center;
            background-color: lightgray; margin-bottom: 10px;}
        .droppable {margin-right: 5px; height: 50px; width: 120px}
        #dropContainer {position: absolute; right: 5px;}
        div span {position: relative; top: 25%}
        .droppable.active {border: medium solid green}
        .droppable.hover {background-color: lightgreen}
    </style>
    <script type="text/javascript">
        $(document).ready(function() {
              
            $("#apple").draggable({
                scope: "fruit"
            });
            $("#orchid").draggable({
                scope: "flower"
            });
              
            $("#flowerDrop").droppable({
                activeClass: "active",
                hoverClass: "hover",
                scope: "flower"
            });
              
            $("#fruitDrop").droppable({
                activeClass: "active",
                hoverClass: "hover",
                scope: "fruit"
            });
        });
    </script>
</head>
<body>
    <h1>Jacqui's Flower Shop</h1>
    <div id="dropContainer">
        <div id="flowerDrop" class="droppable">
            <span>Flowers</span>
        </div>
        <div id="fruitDrop" class="droppable">
            <span>Fruit</span>
        </div>
    </div>
    <div id="orchid" class="draggable">
        <span>Orchid</span>
    </div>
    <div id="apple" class="draggable">
        <span>Apple</span>
    </div>
</body>
</html>

In Listing 24-13, I created two draggable elements and two droppable elements. When creating these elements, I assigned them to one of two scope values: fruit and flower. The result is that each draggable element will activate and be accepted only by the droppable element with the same scope, as shown in Figure 24-12.

9781430263883_Fig24-12.jpg

Figure 24-12. Grouping draggable and droppable elements by scope

image Caution  Notice that I defined the scope for each element in the initial call to the draggable and droppable methods, rather than using the option method. As I write this, there is a bug in jQuery UI where assigning a scope after the interaction has been created doesn’t work.

Using a Helper Element

The helper setting allows you to specify an element that will be dragged in place of the draggable element, leaving the original draggable element in place. This is an entirely different effect from previous examples, where the draggable element has been moved from its original position. Listing 24-14 shows an example of using a helper element.

Listing 24-14.  Using a Large Draggable Element

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <script src="jquery-2.0.2.js" type="text/javascript"></script>
    <script src="jquery-ui-1.10.3.custom.js" type="text/javascript"></script>
    <link rel="stylesheet" type="text/css" href="styles.css"/>
    <link rel="stylesheet" type="text/css" href="jquery-ui-1.10.3.custom.css"/>
    <style type="text/css">
        .draggable, .droppable {font-size: large; border: medium solid black;
            padding: 4px; width: 150px; text-align: center;
            background-color: lightgray; margin-bottom: 10px;}
        .droppable {margin-right: 5px; height: 50px; width: 120px}
        #dropContainer {position: absolute; right: 5px;}
        div span {position: relative; top: 25%}
        .droppable.active {border: medium solid green}
        .droppable.hover {background-color: lightgreen}
    </style>
    <script type="text/javascript">
        $(document).ready(function() {
              
            $("div.draggable").draggable({
                helper: "clone"
            });
              
            $("#basket").droppable({
                activeClass: "active",
                hoverClass: "hover"
            });
        });
    </script>
</head>
<body>
    <h1>Jacqui's Flower Shop</h1>
    <div id="dropContainer">
        <div id="basket" class="droppable">
            <span>Basket</span>
        </div>
    </div>
    <div class="draggable">
        <img src="lily.png"/><label for="lily">Lily</label>
    </div>
</body>
</html>

The value clone tells jQuery UI to make a copy of the draggable element and all of its contents and use the result as the helper element. You can see the effect in Figure 24-13. The helper element is removed when the user drops it, leaving the draggable and droppable elements in their original positions.

9781430263883_Fig24-13.jpg

Figure 24-13. A large draggable element

As the figure shows, the original draggable element remains in position and only the helper is moved across the screen to follow the user’s mouse. Large draggable elements like the one in this example make it difficult for the user to see the underlying elements in the document, including the position of the droppable element. You can address this issue by providing a function as the value for the helper setting, as shown in Listing 24-15.

Listing 24-15.  Using the helper Setting

...
<script type="text/javascript">
    $(document).ready(function() {
          
        $("div.draggable").draggable({
            helper: function() {
                return $("<img src=lily.png />")
            }
        });
          
        $("#basket").droppable({
            activeClass: "active",
            hoverClass: "hover"
        });
    });
</script>
...

When the user starts to drag the element, jQuery UI calls the helper function and uses the element that it returns as the draggable item. In this case, I use jQuery to create an img element. You can see the effect in Figure 24-14.

9781430263883_Fig24-14.jpg

Figure 24-14. Using a helper

The smaller image acts as a more compact stand-in for the draggable element, making it easier to see the rest of the document while dragging.

Manipulating the Helper Element

The ui object that jQuery UI passes to the droppable events contains a helper property, which you can use to manipulate the helper element as it is being dragged. Listing 24-16 shows the use of this property, tied to the over and out events.

Listing 24-16.  Using the ui.helper Property

...
<script type="text/javascript">
    $(document).ready(function() {
          
        $("div.draggable").draggable({
            helper: function() {
                return $("<img src=lily.png />")
            }
        });
          
        $("#basket").droppable({
            over: function(event, ui) {
                ui.helper.css("border", "thick solid green")
            },
            out: function(event, ui) {
                ui.helper.css("border", "")
            }
        });
    });
</script>
...

I use the over and out events and the ui.helper property to display a border on the helper element when it overlaps the droppable element. You can see the result in Figure 24-15.

9781430263883_Fig24-15.jpg

Figure 24-15. Manipulating the helper element

Snapping to the Edges of Elements

You can make the draggable element snap to the edges of the elements that it passes over using the snap setting . The value for this setting is a selector. The draggable will snap to the edges of any element that it is near that matches the selector. Listing 24-17 shows the use of the snap setting.

Listing 24-17.  Using the snap Setting

<!DOCTYPE html>
<html>
<head>
    <title>Example</title>
    <script src="jquery-2.0.2.js" type="text/javascript"></script>
    <script src="jquery-ui-1.10.3.custom.js" type="text/javascript"></script>
    <link rel="stylesheet" type="text/css" href="styles.css"/>
    <link rel="stylesheet" type="text/css" href="jquery-ui-1.10.3.custom.css"/>
    <style type="text/css">
        #snapper, .draggable, .droppable {font-size: large; border: medium solid black;
            padding: 4px; width: 150px; text-align: center;
            background-color: lightgray; margin-bottom: 10px;}
        .droppable {margin-right: 5px; height: 50px; width: 120px}
        #dropContainer {position: absolute; right: 5px;}
        div span {position: relative; top: 25%}
        .droppable.active {border: medium solid green}
        .droppable.hover {background-color: lightgreen}
        #snapper {position: absolute; left: 35%; border: medium solid black;
            width: 180px; height: 50px}
    </style>
    <script type="text/javascript">
        $(document).ready(function() {
              
            $("div.draggable").draggable({
                snap: "#snapper, .droppable",
                snapMode: "both",
                snapTolerance: 50
            });
              
            $("#basket").droppable({
                activeClass: "active",
                hoverClass: "hover"
            });
        });
    </script>
</head>
<body>
    <h1>Jacqui's Flower Shop</h1>
    <div id="dropContainer">
        <div id="basket" class="droppable">
            <span>Basket</span>
        </div>
    </div>
    <div id="snapper"><span>Snap Here</span></div>
    <div class="draggable">
        <span>Drag Me</span>
    </div>
</body>
</html>

As the draggable element nears one of the matching elements, it jumps (snaps) so that the two closest edges touch. You can select any element to snap to, not just droppable elements. In Listing 24-17, I added a div element and defined a value for the snap setting, which selects it and the droppable element in the document. It is pretty much impossible to show the effect of snapping using a screenshot, so I encourage you to experiment with this example in the browser.

There are a couple of supporting settings you can use to tweak the snapping behavior. The first is snapMode . This setting lets you specify which edges the draggable will snap to. The accepted values are inner (snap to the inner edges of the underlying element), outer (snap to the outer edges), and both (snap to all edges, which is the default value).

You use the snapTolerance setting to specify how far the draggable element has to be away from the target before it snaps into position. The default is 20, meaning 20 pixels. In Listing 24-17, I specified a value of 50, which makes snapping occur from further away. Getting the right value for this setting is important. The user won’t notice the snapping effect if the snapTolerance value is too small, and if the value is too large the draggable element starts leaping unexpectedly across the screen to snap to faraway elements

Summary

In this chapter, I introduced you to the two most important and useful of the jQuery UI interactions: draggable and droppable. I showed you how to apply and configure these interactions individually, how to respond to their events, and how to tune the way that they work together to get fine-grained control over the drag-and-drop experience you provide to your web application users. In Chapter 25, I show you the other jQuery UI interactions.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.220.181.146