<!DOCTYPE html>
<html>

  <head>
    <title>Angular 2 QuickStart</title>

    <!-- 1. Load libraries -->
    <script src="https://rawgithub.com/systemjs/systemjs/0.19.6/dist/system.js"></script>
    <script src="https://code.angularjs.org/tools/typescript.js"></script>
    <script src="https://code.angularjs.org/2.0.0-beta.0/angular2-polyfills.js"></script>
    <script src="https://code.angularjs.org/2.0.0-beta.0/Rx.js"></script>
    <script src="https://code.angularjs.org/2.0.0-beta.0/angular2.dev.js"></script>

    <!-- 2. Configure SystemJS -->
    <script>
      System.config({
        transpiler: 'typescript', 
        typescriptOptions: { emitDecoratorMetadata: true }, 
        packages: {'src': {defaultExtension: 'ts'}} 
      });
    </script>

    <!-- 3. Bootstrap -->
    <script>
      System.import('angular2/platform/browser').then(function(ng){
        System.import('src/folder_upload').then(function(src) {
          ng.bootstrap(src.FolderUpload);
        });
      });
    </script>

  </head>

  <!-- 4. Display the application -->
  <body>
    <folder-upload>Loading...</folder-upload>
  </body>

</html>
import {ChangeDetectorRef, Component} from 'angular2/core';

@Component({
  selector: 'folder-upload',
  templateUrl: 'src/folder_upload.html'
})
export class FolderUpload {
  
  canDropFolder = typeof DataTransferItem.prototype.webkitGetAsEntry === 'function';
  uploadPaths = [];
  
  constructor(private cdr: ChangeDetectorRef) {}
  
  dragenter(event) {
    // indicates valid drop data
    // false allows drop
    return Array.prototype.every.call(
      event.dataTransfer.items,
      item => item.kind !== 'file'
    );
  }
  
  dragover(event) {
    // indicates valid drop data
    // false allows drop
    return Array.prototype.every.call(
      event.dataTransfer.items,
      item => item.kind !== 'file'
    );
  }
  
  drop(event) {
    const entries = Array.from(event.dataTransfer.items)
                    .filter(item => item.kind === 'file')
                    .map(item => item.webkitGetAsEntry());
    this.buildTree(entries, '').then(tree => {
      this.uploadPaths = [];
      this.upload(tree, '');
      this.cdr.markForCheck();
    });
    // indicates valid drop data
    // false allows drop
    return false;
  }
  
  filesPicked(files) {
    console.log(files);
    this.uploadPaths = [];
    Array.prototype.forEach.call(files, file => {
      this.uploadPaths.push(file.webkitRelativePath);
    });
  }
  
  private parseFileEntry(fileEntry) {
    return new Promise((resolve, reject) => {
      fileEntry.file(
        file => {
          resolve(file);
        },
        err => {
          reject(err);
        }
      );
    });
  }
  
  private parseDirectoryEntry(directoryEntry) {
    const directoryReader = directoryEntry.createReader();
    return new Promise((resolve, reject) => {
      directoryReader.readEntries(
        entries => {
          resolve(this.buildTree(entries, directoryEntry.name));
        },
        err => {
          reject(err);
        }
      );
    });
  }
  
  private buildTree(entries, name) {
    const tree = {name, files: [], directories: []};
    const promises = [];
    entries.forEach(entry => {
      if (entry.isFile) {
        const promise = this.parseFileEntry(entry).then(file => {
          tree.files.push(file);
        });
        promises.push(promise);
      } else if (entry.isDirectory) {
        const promise = this.parseDirectoryEntry(entry).then(directory => {
          tree.directories.push(directory);
        });
        promises.push(promise);
    });
    return Promise.all(promises).then(() => tree);
  }
  
  private upload(tree, path) {
    tree.files.forEach(file => {
      this.uploadPaths.push(path + file.name);
    });
    tree.directories.forEach(directory => {
      const newPath = path + directory.name + '/';
      this.uploadPaths.push(newPath);
      this.upload(directory, newPath);
    });
  }
}
<link rel="stylesheet" href="folder_upload.css">

<h1>Drop a folder to upload</h1>
<div
  id="drop-area"
  (dragenter)="dragenter($event)"
  (dragover)="dragover($event)"
  (drop)="drop($event)"
>
  <span *ngIf="!canDropFolder">
    Folder Drop Not Supported by Browser
  </span>
</div>


<h1>Select a folder to upload</h1>

<div>
  <input
    #folderInput
    type="file"
    (change)="filesPicked(folderInput.files)"
    webkitDirectory
  >
</div>

<h1 *ngIf="uploadPaths.length > 0">Upload Data</h1>

<div *ngFor="#path of uploadPaths">{{path}}</div>
#drop-area {
  border: 1px solid black;
  width: 300px;
  height: 100px;
}

#drop-area span {
  color: red;
  display: flex;
  justify-content: center;
  margin-top: 10px;
}

#text-output {
  margin-top: 30px;
}