Angular 2 drag and drop directive extremely slow

I am trying to implement a custom drag and drop directive. It works, but it is extremely slow, and I think the slowness can be tracked to Angular 2 because I've never encountered this slowness before. The slowness only occurs when I attach an event listener to the dragover or drag events (i.e. the events which are sent frequently), even if I do nothing but return false in them.

Here's my directive code:

import {Directive, ElementRef, Inject, Injectable} from 'angular2/core';

declare var jQuery: any;
declare var document: any;

@Directive({
    selector: '.my-log',
    host: {
        '(dragstart)': 'onDragStart($event)',
        '(dragover)': 'onDragOver($event)',
        '(dragleave)': 'onDragLeave($event)',
        '(dragenter)': 'onDragEnter($event)',
        '(drop)': 'onDrop($event)',
    }
})
@Injectable()
export class DraggableDirective {
    refcount = 0;
    jel;

    constructor( @Inject(ElementRef) private el: ElementRef) {
        el.nativeElement.setAttribute('draggable', 'true');
        this.jel = jQuery(el.nativeElement);
    }

    onDragStart(ev) {
        ev.dataTransfer.setData('Text', ev.target.id);
    }

    onDragOver(ev) {
        return false;
    }

    onDragEnter(ev) {
        if (this.refcount === 0) {
            this.jel.addClass('my-dragging-over');
        }
        this.refcount++;
    }

    onDragLeave(ev) {
        this.refcount--;
        if (this.refcount === 0) {
            this.jel.removeClass('my-dragging-over');
        }
    }

    onDrop(ev) {
        this.jel.removeClass('my-dragging-over');
        this.refcount = 0;
    }
}

Here's the relevant style sheet excerpt:

.my-log.my-dragging-over {
    background-color: yellow;
}

As you can see all I'm doing is highlighting the element being dragged over in yellow. And it works fast when I don't handle the dragover event, however I must handle it to support dropping. When I do handle the dragover event, everything slows down to unbearable levels!!

EDIT I am using angular beta 2.0.0-beta.8

EDIT #2 I tried profiling the code using chrome's profiler, these are the results:

Look at the marked line, it is strangely suspicious...

EDIT #3 Found the problem: it was indeed due to Angular 2's change detection. The drag and drop operation in my case is done on a very dense page with a lot of bindings and directives. When I commented out everything except the given list, it worked fast again... Now I need your help in finding a solution to this!

EDIT #4 SOLVED

The problem was indeed change detection, but the fault wasn't with Angular's code, but rather with my own inefficient bindings. I had many bindings of this sort:

*ngFor="#a of someFunc()"

This caused Angular to be unsure whether data has changed or not, and the function someFunc was getting called again and again even though data was not changing during the drag and drop process. I changed these bindings to refer to simple properties in my class, and moved the code that populates them where it was supposed to be. Everything started moving lightning fast again!

Thanks!

Just went through some trouble with the same problem. Even with efficient ngFor code, drag and drop can still be crazy slow if you have a large number of draggable items.

The trick for me was to make all drag and drop event listeners run outside of Angular with ngZone, then make it run back in Angular when dropped. This makes Angular avoid checking for detection for every pixel you move the draggable item around.

Inject:

import { Directive, ElementRef, NgZone } from '@angular/core';
constructor(private el: ElementRef, private ngZone: NgZone) {}

Initializing:

ngOnInit() {
  this.ngZone.runOutsideAngular(() => {
    el.addEventListener('dragenter', (e) => {
      // do stuff with e or el
    });
...

On drop:

el.addEventListener('drop', (e) => {
    this.ngZone.run(() => {
        console.log("dropped");
    })
})

Drag & Drop painfully slow performance · Issue #352 · 500tech , My Solution: I reworked the treeDrag and treeDrop directives to make the more common/invasive drag+drop events run outside of Angular, so  Hot answers tagged angular2-directives. day week month year all. 2 <ng-template>,<ng-content> are directives in angular or just angular element?

Answering my own question (problem was solved).

The slowness problem was due to inefficient data bindings in my markup, which caused Angular to waste a lot of time calling functions on my view model. I had many bindings of this sort:

*ngFor="#a of someFunc()"

This caused Angular to be unsure whether data has changed or not, and the function someFunc was getting called again and again after every run of onDragOver (which is a about once every 350ms) even though data was not changing during the drag and drop process. I changed these bindings to refer to simple properties in my class, and moved the code that populates them where it was supposed to be. Everything started moving lightning fast again!

LLAP!

Drag Events Using Directives On Table Row Works Very Slow , In stack trace I found zone js code is getting Executed. The Drag / Drop Events are getting fired very slowly. ://stackoverflow.com/questions/37408247/​angular2-drag-events-using-directives-on-table-row-works-very-slow. Angular 2 drag and drop directive extremely slow I had the same problem with drag & drop in my angular project - detectChanges(reattach(), deTached ..), outSide Angular (ngZone) couldn't solve this problem.

Thanks to everybody for this discussion. End up with simple solution which works like a charm:

constructor(private cd: ChangeDetectorRef) {
}

drag(event: DragEvent): void {
    this.cd.detach();
    // Begin the job (use event.dataTransfer)
}

allowDrop(event: DragEvent): void {
    event.preventDefault();
}

drop(event: DragEvent): void {
    event.preventDefault();
    this.cd.reattach();
    // Do the job
}

Why your drag and drop can be laggy in Angular 2, ngZone example, This directive can be applied for file upload purposes. For more complex drag and drop cases it is better use more advanced ngDragular library. ©  Symptoms: In large Angular applications, the drag and drop for the tree nodes is horrendously slow, even if the tree itself is very small. Problem: There are six different events related to drag and drop, fired constantly as you drag a node around, and each one triggers a full Angular change detection cycle.

I had a similar issue recently. It was in an angular 6 environment using reactive forms. This is how I solved it for my situation:

Basically and briefly, I turned off change detection on that component while dragging was taking place.

  1. import ChangeDetectorRef:
    import { ChangeDetectorRef } from '@angular/core';
  1. inject it into the constructor:
    constructor(private chngDetRef: ChangeDetectorRef) { //...
  1. detach it on dragStart:
    private onDragStart(event, dragSource, dragIndex) {
        // ...
        this.chngDetRef.detach();
        // ...
  1. reattach it on drop and dragEnd:
    private onDrop(event, dragSource, dragIndex) {
        // ...
        this.chngDetRef.reattach();
        // ...

    private onDragEnd(event, dragIndex) {
        // ...
        this.chngDetRef.reattach();
        // ...

If you have a lot of parent or layered components, you may have to do something about their change detection as well in order to see a substantial improvement.

Best of luck!

Drag and Drop in Angular 2 using Native HTML5 API, I decided to create two directives, one to make an element/component draggable (makeDraggable) and the other one to signify that an element/component is a  Latest Free Angular.js components, directives, and modules for drag and drop functionality. Angular Script. Menu. Angular 2 Drag And Drop Module. March 26,

I had a similar issue, also my drag and drop became very slow when I did put multiple drag zones inside a *ngFor.

I solved this by changing the change detection strategy to OnPush of the child component.

Then on every time when an item get dragged, do markForCheck().

constructor(private changeDetectorRef: ChangeDetectorRef) {}
  
// Callback function
public onDrag() {
  this.changeDetectorRef.markForCheck();
}

Exploring Drag and Drop with the new Angular Material CDK, I've heard that Angular Material had a new drag and drop CDK in their upcoming In this release the cdk-drop component is been refactored to a cdkDrop directive. items = [ 'Item 0', 'Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5', 'Item 6', 'Item 7', ] It is useful to wrap objects inside the drag drop event and help in working the application state, and understand how it is connected to the drag drop behaviour. Just bind the the drag directive with the targeted object, additional you can transfer another object by binding into drag-collection You can also bind to the drop directive and the

Drag and Drop, The @angular/cdk/drag-drop module provides you with a way to easily and You can now add the cdkDrag directive to elements to make them draggable. Episode II - Attack of the Clones .cdk-drag-placeholder, This is element that will be shown instead of the real element as it's being dragged inside a cdkDropList . Drag element .drag When drag element hovers another drag element .drag.hover When .drag is being dragged .drag.dragging Drop area .drop When .drag is being dragged appended to .drop .drop.dropable When drag element hovers a drop element .drop.dropable.hover.

ng2-dragula, Whether starting a dragging sequence from this container is disabled. @Input('​cdkDropListEnterPredicate'). enterPredicate: (drag: CdkDrag, drop: CdkDropList) =>  In this blog post I will show you how to roll out simple and reusable drag and drop directives that leverage the HTML 5 Drag and Drop API. If you need a full blown Angular 2 Drag and Drop solution check ng2-dragula or ng2-dnd. Directive vs. Component. We will use attribute directives instead of components this time.

Simple Drag and Drop with Angular 2, angular-dragula There are plenty of events along the lifetime of a drag event. all of them in the docs! A drop event is fired whenever an element is dropped anywhere other than its origin (where it was initially dragged from) Item 2. Item 3. Item 4. <div class="wrapper" dragula="COLUMNS" [(dragulaModel)]="groups">​  Angular-DragDrop is popularly known as an Angular HTML5 Drag and Drop directive. Features: It has no dependency on jQuery; Conclusion. The above mentioned and well explained Angular drag and drop libraries are some of the very important Add-Ons you can consider using whenever you are dealing with an Angular project.

Comments
  • Can you explain in simple terms what the cause of the problem is? I can't understand much from reading the issue...
  • Most likely because the mix of ng2 and jQuery, have you tried relying only in ng2 + RxJS? plnkr.co/edit/LD5FJaI4OOFbKfvhjD4e?p=preview
  • This is not the cause, sorry, I tried removing all traces of jQuery. Same result.
  • Then you'll have to provide a reproduction. I cannot see the same behavior in my plnkr.
  • @EricMartinez here's a plnkr plnkr.co/edit/cY1Adg5M8Ox0Ss4a6jSn?p=preview strangely enough it doesn't happen there!!! would you be willing to look at my original site and see what the difference might be?
  • Finally a solution! Drag'nDrop was painfully slow on a tree structure with many bindings involved. 10-15sec of spinning 'dragover' events was no exception. Thank you.
  • Awesome solution. its very fast.
  • Perfect. Non-angular solution, just shows how angular implementation is and that its doing something else in the background.