Search code examples
ember.jsdrag-and-drophtml5-draggable

Nested Ember.View dragEnter dragLeave called in wrong order?


I am creating a calendar using the html5 drag and drop api.

I am using dragEnter and dragLeave to style the receiving element and determine droppablity.

The receiving droppable element has children and dragLeave is being called when dragging over a child element. This problem is know and described here.

My attempted solution was to add dragLeave and dragEnter events on the children and pass the logic back to the parentView.

Here is the code. http://jsbin.com/iHaNuPo/17

The problem is `dragEnter' on the child is called before 'dragLeave' on the parent.

This is the order of events.

#in from outside parent to over child
1. parent-enter 
2. child-enter 
3. parent-leave
#out from over child to outside parent
1. parent-enter
2. child-leave
3. parent-leave

Is this a bug?

Anyone know a Ember'ish way to prevent the dragLeave event of the parent from firing when hovering over a child?

Or a way to fix the order in which events dragLeave, dragEnter fire?

Should I ditch html5 native drag and drop and use jquery ui draggable/droppable?

EDIT

Here is a working example as per Woody's answer.

http://jsbin.com/OjAGabUj/22


Solution

  • Hopefully this can help you although it's not Ember, maybe you can make use of it. I've had a fair bit of experience of HTML5 drag and drop and it's a bit irksome, but if you want cool stuff like cross window drag and drop it's worth the effort I think.

    var ignoreNextLeave = false;
    
    $("#outerDragTarget").on("dragenter", function(ev) {
       // not interested in dragleaves from my children...
       if (ev.target !== this) {
          ignoreNextLeave = true;
       }
    
       $(this).addClass("dragover");
    
    }).on("dragleave", function(ev) {
    
       if (ignoreNextLeave) {
          ignoreNextLeave = false;
          return;
       }
    
       $(this).removeClass("dragover");
    });
    
    $("#innerDragTarget").on("dragleave", function(ev) {
      ev.stopPropagation();
    });
    

    You can run it here

    The trick is to cancel propagation of dragleaves from the inner element and note that when drag enter fires on the parent and the target is not the parent, we're about to get a drag leave we're not interested in. Not ideal but it could be factored into something you can hopefully use.