angularfile-uploadangular-changedetectionngzone

Angular .nozone file uploader component


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?


Solution

  • 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