Angular Folder Upload (not just multiple files, but the entire directory)

Asked

Viewed 140 times

3

I’m using ngx-admin with Nebular for a Dashboard project.

My following code works well to send multiple files. However an error occurs when trying to send a folder (dragging the folder to the file input)

What I need to change to make it possible to send a directory?

template-sent.component.html

<input type="file" (change)="upload($event.target.files)" multiple="multiple">

<div class="progress">
    <div class="progress-bar" [style.width]="progress + '%'">{{progress}}%</div>
</div>

template-sent.component.ts

import { Component } from "@angular/core";
import {
    HttpClient,
    HttpEventType
} from "@angular/common/http";
import { map, catchError } from "rxjs/operators";
import { throwError } from "rxjs";
import { environment } from "environments/environment";

@Component({
    selector: "template-sent",
    templateUrl: "./template-sent.component.html",
    styleUrls: ["./template-sent.component.scss"]
})
export class TemplateSentComponent {
    progress: number;

    constructor(private http: HttpClient) { }

    upload(file) {
        this.progress = 1;
        const formData = new FormData();

        for (const index in file) {
            if (Object.prototype.hasOwnProperty.call(file, index)) {
                formData.append("files[]", file[index]);
            }
        }

        this.http
            .post(environment.sentTemplateEmail, formData, {
                reportProgress: true,
                observe: "events"
            })
            .pipe(
                map((event: any) => {
                    if (event.type == HttpEventType.UploadProgress) {
                        this.progress = Math.round((100 / event.total) * event.loaded);
                    } else if (event.type == HttpEventType.Response) {
                        this.progress = 100;
                        console.log(event.body);
                    }
                }),
                catchError((err: any) => {
                    this.progress = null;
                    alert(err.message);
                    return throwError(err.message);
                })
            )
            .toPromise();
    }
}

Here’s an example of the idea I want to apply (only with an entire directory, and not just with individual files or multiple files)

Exemplo

1 answer

1


I managed to solve, follows solution for those who have the same difficulty:

In HTML just use the attribute webkitDirectory to allow the sending of a folder. This alone will already solve the problem, causing the script to read each file inside the folder sent, recursively.

template-sent.component.html

<input #folderInput type="file" (change)="upload($event.target.files)" multiple="multiple" webkitDirectory>

However, to send the paths you need to use the property webkitRelativePath of each file, this way:

template-sent.component.ts

...
upload(file) {
        this.progress = 1;
        const formData = new FormData();

        for (const index in file) {
            if (Object.prototype.hasOwnProperty.call(file, index)) {
                // Pega o arquivo atual
                const thisFile = file[index];
                // Grava os dados dele para envio
                formData.append('files[]', thisFile);
                // Garava o path original dele
                formData.append('paths[]', thisFile.webkitRelativePath);
            }
        }
        ...

The result of this sending to the back-end will be 2 fields of type array, files and paths, the first containing the data of the uploaded files and the second containing the complete path of each file, something similar to this:

files:
    error: Array(3) 
        [0, 0, 0]
    name: Array(3) 
        ["imagem1.jpg", "imagem2.jpg", "documento1.docx"]
    size: Array(3) 
        [179686, 179686, 0]
    tmp_name: Array(3) 
        ["D:\xampp\tmp\php289A.tmp", "D:\xampp\tmp\php28AB.tmp", "D:\xampp\tmp\php28AC.tmp"]
    type: Array(3) 
        ["image/jpeg", "image/jpeg", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"]

paths: Array(3)
    0: "pasta-exemplo/imagem1.jpg"
    1: "pasta-exemplo/imagem2.jpg"
    2: "pasta-exemplo/sub-pasta/documento1.docx"

Upshot Resultado

Source: https://www.lucidchart.com/techblog/2018/01/03/folder-upload-in-an-angular-app/

  • 1

    Very good! Thank you, I was needing this too

Browser other questions tagged

You are not signed in. Login or sign up in order to post.