Newton Zou
Newton Zou

Reputation: 588

How to wrap FileSystemFileEntry.file into a function that returns Observable?

I'm trying to read files recursively from the dropped folder.

onDrop(event) {
  event.preventDefault();
  this.folderData = [];
  this.filesData = [];

    const items = event.dataTransfer.items;
    for (let i = 0; i < items.length; i++) {
      const item = items[i].webkitGetAsEntry();
      if (item) {
        this.scanFiles(item, this.folderData);
      }
    }
    // send out data
    // this.dropped.emit({ folderData: this.folderData, filesData: this.filesData });
}

private scanFiles(item, container: Array<any>) {
  const nodeData = {
    name: item.name,
    isDirectory: item.isDirectory,
    item: item,
    children: []
  };

  container.push(nodeData);
  if (item.isDirectory) {
    const directoryReader = item.createReader();
    directoryReader.readEntries(entries => {
      if (entries) {
        entries.forEach(entry => this.scanFiles(entry, nodeData.children));
      }
    });
  } else if (item.isFile) {
    // How to return an Observable array here? 
    item.file(file => {
      file.fullPath = item.fullPath;
      this.filesData.push(file);
    });
  }

}

According to MDN, FileSystemFileEntry.file returns the result in its callback. https://developer.mozilla.org/en-US/docs/Web/API/FileSystemFileEntry/file

So before onDrop sends out the result, it has to wait, until all the FileSystemFileEntry.file callbacks complete.

I want to use Observable.forkJoin to achieve this. But before that, how to wrap FileSystemFileEntry.file into a function that returns Observable?

Upvotes: 3

Views: 1420

Answers (1)

Newton Zou
Newton Zou

Reputation: 588

It turns out that a single forkJoin can't resolve the problem. I finally complete this by recursive forkJoin.

onDrop(event) {
  event.preventDefault();
  this.folderData = [];
  this.filesData = [];

  const items = event.dataTransfer.items;
  const obs = [];
  for (let i = 0; i < items.length; i++) {
    const item = items[i].webkitGetAsEntry();
    if (item) {
      obs.push(new Observable<any>(observer => this.scanFiles(item, this.folderData, observer)));
    }
  }

  forkJoin(obs).subscribe(e => {
    this.dropped.emit({ folderData: this.folderData, filesData: this.filesData });
  });
}

private scanFiles(item, container: Array<any>, observer: Subscriber<any>) {
const nodeData = {
  name: item.name,
  isDirectory: item.isDirectory,
  item: item,
  children: []
};

container.push(nodeData);
if (item.isDirectory) {
  const directoryReader = item.createReader();
  directoryReader.readEntries(entries => {
    if (entries) {
      if (entries.length === 0) {
        observer.next();
        observer.complete();
      } else {
        const subObs = entries.map(entry => new Observable<any>(innerObserver =>
          this.scanFiles(entry, nodeData.children, innerObserver)));
        forkJoin(subObs).subscribe(e => {
          observer.next();
          observer.complete();
        });
      }
    } else {
      observer.next();
      observer.complete();
    }
  });
} else if (item.isFile) {
  item.file(file => {
      file.fullPath = item.fullPath;
      this.filesData.push(file);
      observer.next();
      observer.complete();
  });
}

}

For more detial check https://github.com/ft115637850/ngx-folder-uploader.

Upvotes: 2

Related Questions