Padraig
Padraig

Reputation: 3707

How do I prevent click event when I cancel drag in jquery UI?

My intent is to have a series of folders and sub items (like a directory tree) and drag and drop the items to rearrange. When I simply click on a folder (a list item with a child ul) it should either slide open or slide close.

The problem is : I want to prevent the click event when I cancel a drag.

By cancel - I mean I start to drag the element, and then release the mouse without dropping it on top of any droppables.

My first guess was using event.stopImmediatePropagation() and event.stopPropagation(). This indeed prevents the click event when I cancel drags on list items that have no ul children.

However, when I cancel drag on li's that have ul children, the default click behavior occurs (which in this case is slideToggle).

How do I prevent the click event when I cancel drag of an li with ul children?

$("li").click(function (event) {
    console.log($(this).attr("class"));
    if ($(this).children("ul").length > 0) $(this).children("ul").slideToggle();
    event.stopPropagation();
    event.stopImmediatePropagation();
    event.preventDefault();
})

$("li").draggable({
    rever: false,
    helper: "clone",
    cursorAt: {
        top: -1,
        left: -1
    },
    stop: function (event) {
        event.stopPropagation();
        event.stopImmediatePropagation();
    }
});

$("span").droppable({
    hoverClass: "ui-state-active",
    greedy: true,
    tolerance: "pointer",
    drop: function (event, ui) {
        var dragged = ui.draggable
        var target = $(this).parent()

        if (target.children("ul").length == 1) {
            dragged.appendTo(target.children("ul"));
        } else {
            // depends upon whether I'm dragging from above or from below
            if (dragged.prev().is(target)) // dragging from below
            dragged.insertBefore(target)
            else dragged.insertAfter(target)
        }

        event.stopPropagation();
    },
});

Full code in JSFiddle

Upvotes: 1

Views: 1163

Answers (1)

T J
T J

Reputation: 43156

One way to get around is to use separate elements to trigger both the actions.

For example, we use the handle option.

If specified, restricts dragging from starting unless the mousedown occurs on the specified element(s). Only elements that descend from the draggable element are permitted

To trigger the dragging, and a separate <span> element to trigger the toggle functionality.

Updated Fiddle (Click the text for dragging and +/- for toggling)


Another hackish work around is to keep track of a boolean flag -

We can set a boolean to true when dragging starts, and set it back to false after a tiny timeout inside the stop callback.

The click event will be triggered immediately when we release the mouse - So if the click is triggered by a drag, the boolean flag will still be true since we'll only reset it after a short timeout. If it is a normal click - the flag will be false.

Updated Fiddle


var dragging = false;
$("li").click(function (event) {
    event.stopPropagation();
    $this = $(this);
    console.log(dragging);
    if (!dragging) {
        if ($this.children("ul").length > 0) $this.children("ul").slideToggle();
    }
});

$("li").draggable({
    revert: false,
    helper: "clone",
    cursorAt: {
        top: -1,
        left: -1
    },
    start: function (event) {
        dragging = true;
    },
    stop: function (event) {
        setTimeout(function () {
            dragging = false;
        }, 10);
    }
});

$("span").droppable({
    hoverClass: "ui-state-active",
    greedy: true,
    tolerance: "pointer",
    drop: function (event, ui) {
        var dragged = ui.draggable
        var target = $(this).parent()

        if (target.children("ul").length == 1) {
            dragged.appendTo(target.children("ul"));
        } else {
            // depends upon whether I'm dragging from above or from below
            if (dragged.prev().is(target)) // dragging from below
            dragged.insertBefore(target)
            else dragged.insertAfter(target)
        }

        event.stopPropagation();
    },
});
.ui-state-active {
     background-color : red;
 }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<ul>
    <li><span>Test 1</span>

    </li>
    <li> <span>Test 2</span>

        <ul>
            <li class="A"><span>Test A</span>

            </li>
            <li class="B"><span>Test B</span>

            </li>
            <li class="C"><span>Test C</span>

            </li>
        </ul>
    </li>
    <li><span>Test 3</span>

    </li>
    <li> <span>Test 4</span>

        <ul>
            <li><span>Test X</span>

            </li>
            <li><span>Test Y</span>

                <ul>
                    <li><span>F</span>

                    </li>
                    <li><span>G</span>

                    </li>
                    <li><span>H</span>

                    </li>
                </ul>
            </li>
            <li><span>Test Z</span>

            </li>
        </ul>
    </li>
</ul>

Upvotes: 1

Related Questions