Reputation: 588
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
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