Luckylooke
Luckylooke

Reputation: 4539

HTML5 native DragEnter/DragLeave Events keep firing alternatively

I am using native HTML drag'n'drop in my angular app and I found this event flickering problem

This answer doesnt solve my issue, as they are moving the element manualy. I am leaving it on native implementation.

My simplified code:

var app = angular.module('app', []);
app.directive('amDnd', function() {
  return {
    scope: true,
    link: function($scope, $element, $attr) {
      var el = $element[0];
      el.draggable = true;

      el.addEventListener('dragenter', function dragEnter(e) {
        console.log($scope.$id, 'dragEnter');
      }, false);
      el.addEventListener('dragleave', function dragEnter(e) {
        console.log($scope.$id, 'dragleave');
      }, false);

    }
  };
});
div[am-dnd] {
  border: 2px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
  <div am-dnd>
    <p>DRAG ME</p>
  </div>
  <div am-dnd>
    <h3>DRAG OVER THIS AREA</h3>
    <p>See the console, drag enter and leave are fired again and again while draging over
    </p>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi quisquam, eaque, iure mollitia similique magnam voluptatem blanditiis distinctio nemo! Laboriosam porro iste maiores sequi magnam similique ad, in at. Omnis.</p>
  </div>

</div>

Upvotes: 4

Views: 4195

Answers (2)

Luckylooke
Luckylooke

Reputation: 4539

Solution which best fits my needs:

var app = angular.module('app', []);
app.directive('amDnd', function() {
  return {
    scope: true,
    link: function($scope, $element, $attr) {
      var el = $element[0],
        counter = 0;
      el.draggable = true;

      el.addEventListener('dragenter', function dragEnter(e) {
        if (e.target === el && !counter) {
          console.log($scope.$id, 'dragEnter');
        }
        counter++;
      }, false);
      el.addEventListener('dragleave', function dragLeave(e) {
        counter--;
        if (e.target === el && !counter) {
          console.log($scope.$id, 'dragleave');
        }
      }, false);

    }
  };
});
div[am-dnd] {
  border: 2px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
  <div am-dnd id='id1'>
    <p>DRAG ME</p>
  </div>
  <div am-dnd id='id2'>
    <h3>DRAG OVER THIS AREA</h3>
    <p>See the console, drag enter and leave are fired again and again while draging over
    </p>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi quisquam, eaque, iure mollitia similique magnam voluptatem blanditiis distinctio nemo! Laboriosam porro iste maiores sequi magnam similique ad, in at. Omnis.</p>
  </div>

</div>

Upvotes: 1

alex
alex

Reputation: 7433

I've got a feeling that root of the "flickering" issue is that the dragenter/dragleave events are occurring for each child element of the second am-dnd directive. There's a Stack Overflow question that discusses fixes for this here.

You might be able to declare a CSS rule like this:

.child-elements {
   pointer-events: none;
}

... and apply this class to all child elements of the am-dnd directive using jqLite during the event trigger:

element.children().addClass("child-elements");

I made a JSFiddle where the "flickering" events are minimized when the first directive is dragged over the second, but there's still some issues with the second directive being dragged over the first. Nevertheless, I hope this points you in the right direction.

var app = angular.module('app', []);
app.directive('amDnd', function () {
    return {
        scope: true,
        link: function (scope, element, attrs) {
            element.attr('draggable', 'true');

            element.on('dragenter', function () {
                element.children().addClass("child-elements");
                console.log('dragEnter');
            });
            element.on('dragleave', function () {
                element.children().removeClass("child-elements");
                console.log('dragleave');
            });
        }
    };
});

Upvotes: 5

Related Questions