0

I'm working in Angular 7 trying to create a drag and drop file upload component. I have it working below.

public stopPreventAndSetClass(b: boolean, event: any): void {
    if (event.target === this.enterTarget) {
        this.draggedOverTable = b;
    }
    console.log(event.target);
    this.stopAndPrevent(event);
}

public stopAndPrevent($event: any): void {
    event.preventDefault();
    event.stopPropagation();
}
<div class="document-container"
    (drop)="saveFiles($event); stopPreventAndSetClass(false, $event)"
    (dragenter)="enterTarget = $event.target; stopPreventAndSetClass(true, $event)"
    (dragover)="stopAndPrevent($event);"
    (dragleave)="stopPreventAndSetClass(false, $event)"
    [ngClass]="{'showDropContainerBorder': draggedOverTable}">
    <!-- An Angular Material table of uploaded files sits here. So think many child elements. -->
</div>

My problem is that the performance on this is awful (~4 second lag time between drop and saveFiles() running) because change detection is running for every dragover and dragleave event fired. After doing a good amount of research, I found that the best solution is supposedly to remove the dragover event from the ngzone which will prevent the change detection from firing. From here: https://github.com/angular/angular/pull/21681 A very easy way of doing this seems to be (dragover.nozone)="stopAndPrevent($event)". This does fix the performance issue, but it also no longer works, as the browser reverts back to using its default behavior (loading file in browser) ignoring the event.preventDefault();. Does anyone know of a better way to do this or know how to fix the performance issue I'm running into here?

flywing314
  • 31
  • 4

2 Answers2

0

Found a solution. Blacklisting dragover events from zone.js by following https://github.com/JiaLiPassion/blacklist/blob/master/src/index.html and adding

<script>
    var targets = [window, Document, HTMLBodyElement, HTMLElement];
    __Zone_ignore_on_properties = [];
    targets.forEach(function (target) {
      __Zone_ignore_on_properties.push({
        target: target,
        ignoreProperties: ['dragover']
      });
    });
    __zone_symbol__BLACK_LISTED_EVENTS = ['dragover'];
    __Zone_disable_requestAnimationFrame = true;
</script>

to my index.html

flywing314
  • 31
  • 4
0

You can use throttle from lodash-decorators. It will prevent the decorated function from running more often than the amount of milliseconds you give it as a parameter.

@Throttle(300) public stopPreventAndSetClass(b: boolean, event: any): void {
   //...
}
Adam Genshaft
  • 756
  • 10
  • 22