0

I am encountering a strange issue with Angular 2 change detection when using a recursive function to read user drag & dropped files.

Refer to here for the example:

File drop example: plnkr.co

In the example above, there are two file drop areas. The top area uses a recursive function to read all files in user dropped items. The bottom area simply use dataTransfer.files.

The files dropped is supposed to be displayed bellow. However, change detection only works for the bottom drop area.

This is a simplified version of my actual application. I am not keen to use ChangeDetectorRef to trigger the detection (I know it will work for the plunker example).

Is there a better way to read all the files dropped in (including files in subfolders) with webkitGetAsEntry()? Or another way will work with Angular change detection?

I am on Angular 2.4.9.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Northern
  • 2,338
  • 1
  • 17
  • 20
  • You need to run code inside angular zone http://take.ms/bbKa3 – yurzui Mar 10 '17 at 15:41
  • @yurzui thanks! But do you know why the recursive function is running outside `NgZone`? – Northern Mar 10 '17 at 16:05
  • angular(zonejs) doesn't patch `FileEntry.file` – yurzui Mar 10 '17 at 16:19
  • @yurzui Can you elaborate more on what do you mean by "doesn't patch FileEntry.file"? I also have another call of `this.addFiles(files)`, which is running fine within `NgZone`. The only difference I can see is that the second call is in the recursive function. – Northern Mar 10 '17 at 17:02

1 Answers1

0

Replace the code in app.ts with the code below and it will work. Zone.js will detect changes after the callback has been executed.

//our root app component
import {Component, NgModule,NgZone} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'
import { FileDropDirective } from './file.drop.directive'

@Component({
  selector: 'my-app',
  template: `
    <div>
      <div file-drop class="drop-area" readAsItems="yes" 
      (droppedFiles)="onFilesDrop($event)">Recursive func</div>
      <div file-drop class="drop-area" 
      (droppedFiles)="onFilesDrop($event)">Non-recursive func</div>
      <div *ngFor="let f of files">{{ f }}</div>
    </div>
  `,
  styles: [`
    .drop-area {
      width: 100%;
      height: 20vh;
      background-color: #f1f1f1;
      border: 1px solid red;
      margin: 5px 0;
    }
  `]
})
export class App {
  name:string;
  files: string[];
  constructor(private zone:NgZone) {
    this.name = 'Angular2'
    this.files = [];
  }

  onFilesDrop(files) {
    this.zone.run(()=>{
      files.forEach((f) => {
        this.files.push(f.name);
      })
      console.log(this.files);
    });
  }
}

@NgModule({
  imports: [ BrowserModule ],
  declarations: [ App, FileDropDirective ],
  bootstrap: [ App ]
})
export class AppModule {}
nekkon
  • 107
  • 1
  • 6
  • Thanks for the answer. I think the yurzui's comments above give a better suggestion. The file drop directive will be potentially used by many components. It is better to fix the change detection in the directive itself than in all the components using it. I am still not sure why the recursive function is running outside `NgZone`. Please let me know if you do. – Northern Mar 10 '17 at 16:11