1

I'm making a jQuery UI sortable and I need to detect when an element is dragged out of it. Sounds EXACTLY like a job for the out event - except for one tiny remark that I myself missed initially:

Note: This event is also triggered when a sortable item is dropped.

This is a major showstopper for me. Whenever the items are merely rearranged, the dragged item still gets an out event in the end. I've been racking my brain but so far to no awail. How do I detect if an out event is because the item was really dragged outside, or wheter it's just because the drag operation is stopping?

(If it matters, jQuery UI version 1.11.4)

Added:

OK, I think I myself fell victim to the "just the last nonsensical part left" trap. What I was trying to do was to have two sortables that can have items dragged between them. Like the example, but with the placeholder disappearing completely when the item is dragged outside all sortables. Which is why I wanted to keep track of which items are inside and which items are outside.

The way I solved it in the end was to drop this "requirement". It's better anyway if the placeholder stays, because it shows where the item will get dropped to when the mouse is released - even when it is outside.

If I did want to keep to this path however, I now see that the correct solution would be to hide the placeholder on an out event, and show it on an over event. There's an over even when the dragging starts, although no item is being dragged in from the outside.

Either way, although both approaches would solve my real problem, neither of them really answer the question that I asked, so I'll let it stay.

Vilx-
  • 104,512
  • 87
  • 279
  • 422
  • When you encounter an `out` event, you cna see if a placeholder exists and remove it. Part of `over` is `ui.sender` as well as `ui.position`. So you can find the sortable you are over with position, if the `ui.position` is within the boundaries, then that target gets the placeholder. – Twisty Aug 21 '18 at 15:49

2 Answers2

1

Not sure if I am hitting the mark here and there are some other pitfalls.

Example: https://jsfiddle.net/Twisty/83Lwxkrs/

JavaScript

$(function() {
  $("#sortable1, #sortable2").sortable({
    connectWith: ".connectedSortable",
    placeholder: "sortable-placeholder",
    out: function(e, ui) {
      $(".sortable-placeholder").remove();
    }
  }).disableSelection();
});

out can be used to remove the placeholder. So when a dragged item leaves, poof, placeholder is gone. When it is dragged over another or the same, poof, placeholder is recreated.

Pitfall: Dropping the item outside of any sortable, the item drops to nothing. The placeholder is removed and so is the dragged item. I suspect this can be fixed, either by looking for drop or mouse up and recreating the placeholder before sortable tries to revert the position.

Twisty
  • 30,304
  • 2
  • 26
  • 45
  • I would try `display:none`. However, that's not what the question was about. If it's confusing though, maybe I'd better delete it. – Vilx- Aug 21 '18 at 21:05
  • @Vilx- you mentioned, "*with the placeholder disappearing completely when the item is dragged outside all sortables*" Is that what the question about? This answer addresses that. – Twisty Aug 21 '18 at 22:10
  • That is what I _wanted_ to achieve. In fact, at first I didn't even realize that _that_ was what I wanted. But what I _asked_ was how to reliably detect (get an event) when an item is actually dragged outside its sortable container. – Vilx- Aug 21 '18 at 23:19
  • @Vilx- todetermine if the `out` event is being triggered in the manner you mentioned in your post, you will need to compare it's current position to the position of the element it's leaving. You could also try something with `.on()` and look at both events. – Twisty Aug 22 '18 at 00:30
0

I think that is the right answer:

var interval;
var outside = false
$(button).addEventListener('mousedown',function(e) {
    interval = setInterval(function() {
        if (outside) {
            //fire event
        }
    },1000); // 1000 ms between each frame
});
// This code will stop the interval if you move your mouse away from the field while still holding it.
$(button).addEventListener('mouseout',function(e) {
    outside = true;
    clearInterval(); //function to clear interval
});
Rafalsonn
  • 430
  • 7
  • 23
  • Hmm... so, if a `mouseup` was registered before the `out`, then ignore the `out`? I suppose that's one way... I'm also checking out `beforeStop` - seems that it too triggers before the `out`. – Vilx- Aug 21 '18 at 09:39
  • I think You should combine mouseup and out in a logic expression – Rafalsonn Aug 21 '18 at 09:40
  • Ermm... I'm not sure what you mean. Maybe give an example? – Vilx- Aug 21 '18 at 09:40
  • Hmmm, wait, maybe next way: https://stackoverflow.com/questions/25180332/how-can-i-listen-for-a-click-and-hold-in-angularjs If user was holding click, the item goes out the screen, and he is not clicking, then trigger your own action – Rafalsonn Aug 21 '18 at 09:42
  • That's Angular... Not even remotely relevant. :/ – Vilx- Aug 21 '18 at 10:11
  • Sorry, I'm often working with angular, habits. https://stackoverflow.com/questions/16707170/mousehold-event-in-jquery combine this with out – Rafalsonn Aug 21 '18 at 10:15
  • OK, but... I don't see what this has to do with my question? That one is about firing an event repeatedly while the mouse is being held down. My question is about reliably detecting when an item has been dragged outside its container. – Vilx- Aug 21 '18 at 10:39
  • I'm not sure this would work, because the mouse would stay on the dragged element which itself would stay a child of the container, so `mouseout` would fire on neither. – Vilx- Aug 21 '18 at 12:07