desandro / draggabilly

:point_down: Make that shiz draggable
https://draggabilly.desandro.com
MIT License
3.86k stars 386 forks source link

How to manually stop dragging? #177

Closed subversivo58 closed 2 years ago

subversivo58 commented 6 years ago

How to leave the event if a given condition is reached?

example:

$('#element').draggabilly({
    containment: true,
    axis: 'x'
}).on('dragMove', function() {
    let containerWidth = $(this).parent().width()
    let buttonWidth = $(this).outerWidth()
    let max = (containerWidth - buttonWidth) - 1 // count border right (1px)
    // condiction
    if ( $(this).position().left >= max ) {
        console.log('limit reached')
        return false // escape here!!! don't escaped!
    }
}).on('dragEnd', function() {
    let containerWidth = $(this).parent().width()
    let buttonWidth = $(this).outerWidth()
    let max = (containerWidth - buttonWidth) - 1 // count border right (1px)
    // confirm condiction
    if ( $(this).position().left >= max ) {
        // do stuff...
    } else {
        // do stuff...
    }
}).on('click', function() {
    //...
})

I'm assuming that return on "move" would trigger "end"? Is there a correct method?

desandro commented 6 years ago

Thanks for reporting this issue. Could you back up and describe what kind of behavior you are trying to achieve?

subversivo58 commented 6 years ago

I'm trying to get out of the event after reaching a given condition.

In the above example I am using a button inside a container in a form trying to create a "slide to submit" function ... so I am computing the measure taken in "dragMove" to see if the button has reached the end.

slide

Using as an example jQuery UI (draggable) and return false inside the "drag" event makes it possible to drop into "stop"... example:

$( "#element" ).draggable({
    cancel: false,
    containment: 'parent',
    axis: 'x',
    start: function(event, ui) {
        console.log('start')
    },
    drag: function(event, ui) {
        let containerWidth = $(this).parent().width()
        let buttonWidth = $(this).outerWidth()
        let max = (containerWidth - buttonWidth) - 1 // count border right (1px)
        // condiction
        if ( $(this).position().left >= max ) {
            console.log('limit reached')
            return false // escape here!!! 
        }
    },
    stop: function(event, ui) {
        console.log('end')
    }
}).on("click", function(evt) {
    // prevent event submit
    evt.preventDefault()
})
/**
  assuming that the move has occurred and the "drag" event has been
  triggered the output will be something like:

  > start
  > limit reached
  > end
 */

I can just test case in this PEN

Using return false in Draggabilly within the "dragMove" event is not falling on "dragEnd" and the observer (the event handler) is not being disabled.

$('#element').draggabilly({
   containment: true,
   axis: 'x'
}).on('dragStart', function() {
   console.log('start')
}).on('dragMove', function() {
   let containerWidth = $(this).parent().width()
   let buttonWidth = $(this).outerWidth()
   let max = (containerWidth - buttonWidth) - 1 // count border right (1px)
   // condiction
   if ( $(this).position().left >= max ) {
       console.log('limit reached')
       return false // escape here!!! don't escaped!
   }
}).on('dragEnd', function() {
   console.log('end')
}).on('click', function(evt) {
   //...
   evt.preventDefault()
})
/**
  assuming that the move has occurred and the "drag" event has been
  triggered the output will be something like:

  > start
  > limit reached

  // this only occurs at the end of the "click" is not being triggered with "return false"
  > end
 */

View this PEN ... on reaching the end (the button) is being used return false but is not terminating the "dragMove" event.

I'm currently using a code snippet written in Vanilla to get the result I want but I have no intention of "reinventing the wheel" ... I liked this library it is much more compact than jQuery Ui and it allows to observe numerous events.

Maybe I did not understand the correct functioning of the library but I think my question is logical. No?

Thank you in advance for your attention and patience.

desandro commented 6 years ago

Thanks so much for you description and CodePens!

Bad news there is no good API to manually stop dragging. Good news is that you can hack it by calling a private method _pointerUp within dragMove:

var $submitBtn = $('#submit-btn').draggabilly({
   containment: true,
   axis: 'x'
})

var draggie = $submitBtn.data('draggabilly');

$submitBtn.on('dragMove', function( event, pointer ) {
   let containerWidth = $(this).parent().width()
   let buttonWidth = $(this).outerWidth()
   let max = (containerWidth - buttonWidth) - 1 // count border right (1px)
   // condition
   if ( draggie.position.x >= max ) {
       draggie._pointerUp( event.originalEvent, pointer );
   }
})

See demo https://codepen.io/desandro/pen/RxJrra/


Add a 👍 reaction to this issue if you would like to see Draggabilly get a dragStop method added. Do not add +1 comments — They will be deleted.

subversivo58 commented 6 years ago

Great.

I really liked the approach, thank you for your attention, that solves the issue.

kmaas2000 commented 6 years ago

This helped with my containment issue...thanks!

desandro commented 2 years ago

Draggabilly v3 has been released with revised dragEnd method. Use it to stop dragging

// jQuery
$draggable.draggabilly('dragEnd')
// vanilla JS
draggie.dragEnd()
rawthriver commented 2 years ago

Unfortunately, v3 + dragEnd still buggy. Does not restore position after dragEnd call. I return back to _pointerUp hack and v2.

desandro commented 2 years ago

@rawthriver Can you put together a CodePen showing what behavior you would like?

rawthriver commented 2 years ago

Here it is https://codepen.io/rawthriver/pen/qBPGGbM Try to drag item 2 on stamped item 1. Using v3 we have item 2 stuck over item 1. Using v2 with _pointerUp it works fine, item 2 goes back.