Skip to content

ZouYouShun/ngxf-uploader

Repository files navigation

NPM version

ngxf-uploader

File uploader for Angular 6+, just use Angular HttpClient, no other dependence. GitHub

  • file upload
  • multiple File upload
  • accept support
  • Progress support
  • upload http request support
  • folder upload, thanks for SHANG-TING, more detail about file upload with folder, can view his blog

Stackblitz Example

Stackblitz

Future

[
  {
    "name": "folder name",
    "files": [...files],
  }
]

Description

Select file or Drop, Paste file, and return an Observable. You can custom your behavior use RxJs 7.x .

Provide an sample way for upload by custom options like header, params, fields, file's form name.

Example

Install

npm install ngxf-uploader --save
  • Import HttpClientModule, NgxfUploaderModule into your main AppModule or the module where you want use.
import { provideHttpClient } from '@angular/common/http';
import { provideExperimentalZonelessChangeDetection, model, inject } from '@angular/core';

import { of, catchError, finalize, tap } from 'rxjs';

import { ChangeDetectionStrategy, Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { FileError, NgxfDirectoryStructure, NgxfDropDirective, NgxfSelectDirective, NgxfUploaderService, UploadEvent, UploadStatus, NgxfParseDirective } from 'ngxf-uploader';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [NgxfSelectDirective, NgxfDropDirective, NgxfParseDirective],
  templateUrl: './app.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class App {
  progress = 0;
  isUploading = false;
  upload = inject(NgxfUploaderService);

  uploadFile(file: File | File[] | NgxfDirectoryStructure[] | FileError) {
    console.log(file);
    this.isUploading = true;

    if (!(file instanceof File) || Array.isArray(file)) {
      // this.alertError(file);
      this.isUploading = false;
      return;
    }

    this.upload
      .upload({
        url: 'your api url',
        headers: {
          Authorization: 'token',
        }, // Option
        params: {
          test: '123',
        }, // Option
        fields: {
          // Option
          toUrl: 'device',
        },
        filesKey: 'fileKey', // Option
        files: file,
        process: true,
      })
      .pipe(
        tap((event: UploadEvent) => {
          console.log(event);
          this.progress = event.percent || 0;

          if (event.status === UploadStatus.Completed) {
            alert(`This file upload success!`);
          }
        }),
        catchError((err) => {
          console.error(err);
          // alert(`upload fail`);
          return of(null);
        }),
        finalize(() => {
          console.log('end');
        }),
      )
      .subscribe();
  }

  // Do something you want when file error occur.
  alertError(msg: FileError) {
    switch (msg) {
      case FileError.NumError:
        alert('Number Error');
        break;
      case FileError.SizeError:
        alert('Size Error');
        break;
      case FileError.TypeError:
        alert('Type Error');
        break;
    }
  }
}

bootstrapApplication(App, {
  providers: [provideHttpClient(), provideExperimentalZonelessChangeDetection()],
});
  • Add directive in the template where you want to use.
<!-- select file -->
<button (ngxf-select)="uploadFile($event)">Upload Single File</button>

<!-- drop file & parse image -->
<div (ngxf-drop)="uploadFiles($event)" (ngxf-parse)="uploadFiles($event)" [ngxf-validate]="{size: {min: 5000, max:2566621}, skipInvalid: true}" drop-class="drop" accept="image/*" multiple>
  <h3>Drop file and parse image into here or click here to choice file.</h3>
</div>
  • Add NgxfUploaderService in the constructor and create file upload method in the typescript and upload file to server.
import { Component } from '@angular/core';
import { FileError, NgxfUploaderService, UploadEvent, UploadStatus } from 'ngxf-uploader';

@Component({
  selector: 'app-drop-file',
  templateUrl: './drop-file.component.html',
  styleUrls: ['./drop-file.component.scss'],
})
export class DropFileComponent {
  progress = 0;
  isUploading = false;

  constructor(private Upload: NgxfUploaderService) {}

  uploadFile(file: File | FileError): void {
    console.log(file);
    this.isUploading = true;
    if (!(file instanceof File)) {
      this.alertError(file);
      this.isUploading = false;
      return;
    }
    this.Upload.upload({
      url: 'your api url',
      headers: {
        Authorization: 'token',
      }, // Option
      params: {
        test: '123',
      }, // Option
      fields: {
        // Option
        toUrl: 'device',
      },
      filesKey: 'fileKey', // Option
      files: file,
      process: true,
    }).subscribe(
      (event: UploadEvent) => {
        console.log(event);
        this.progress = event.percent;
        if (event.status === UploadStatus.Completed) {
          alert(`This file upload success!`);
        }
      },
      (err) => {
        console.log(err);
      },
      () => {
        this.isUploading = false;
        console.log('complete');
      },
    );
  }

  uploadFiles(files: File[] | FileError): void {
    console.log(files);
    this.isUploading = true;
    if (!(files instanceof Array)) {
      this.alertError(files);
      this.isUploading = false;
      return;
    }
    this.Upload.upload({
      url: 'your api url',
      headers: {
        Authorization: 'token',
      }, // Option
      params: {
        test: '123',
      }, // Option
      fields: {
        // Option
        toUrl: 'device',
      },
      filesKey: 'fileKey', // Option
      files: files,
      process: true, // if you want process event, set process true
    }).subscribe(
      (event: UploadEvent) => {
        console.log(event);
        this.progress = event.percent;
        if (event.status === UploadStatus.Completed) {
          alert(`upload complete!`);
        }
      },
      (err) => {
        console.log(err);
      },
      () => {
        this.isUploading = false;
        console.log('complete');
      },
    );
  }

  // Do something you want when file error occur.
  alertError(msg: FileError) {
    switch (msg) {
      case FileError.NumError:
        alert('Number Error');
        break;
      case FileError.SizeError:
        alert('Size Error');
        break;
      case FileError.TypeError:
        alert('Type Error');
        break;
    }
  }
}

API

Attribute Detail

Attribute necessary(default) type position description
(ngxf-select) yes (Array)=>File or FileError any tag provide a directive that can let you select file upload by click
(ngxf-drop) yes (Array)=>File[] or FileError any tag provide a directive for you to set area can be drop file into
(ngxf-parse) yes (Array)=>File[] or FileError any tag provide a directive for you to set area can be parse file into
[ngxf-validate] no FileOption with (ngxf-drop) and (ngxf-select) file validate with file size, and other options
[drop-class] no('drop') string with (ngxf-drop) and (ngxf-select) when drop on tag, this class will append on it
[accept] no string with (ngxf-drop) and (ngxf-select) accept file type
[multiple] no boolean with (ngxf-drop) and (ngxf-select) is allow multiple file
[folder] no boolean (ngxf-select) is allow select folder file
[structure] no boolean (ngxf-drop) show the structure of all folders and files with the new feature of dragging folders.

Service Upload Method

This method will return an Observable<UploadEvent>, that you can subscribe it, and return a UploadEvent.

upload(d: UploadObject): Observable<UploadEvent>;

Upload Object

export interface UploadObject {
  /** target upload api url */
  url: string;
  /** upload file or files, also support Blob */
  files: File | File[] | Blob | Blob[];
  /**
   * target file key name
   *
   * @default
   * 'file'
   */
  filesKey?: string | string[];
  /** is that need report upload progress,
   *
   * @default
   * false
   */
  process?: boolean;
  /** other fields that you want to attach together */
  fields?: any;
  /** other headers that you want to attach together */
  headers?: { [name: string]: string | string[] } | HttpHeaders;
  /** other params that you want to attach together */
  params?: { [name: string]: string | string[] } | HttpParams;
  /** response type */
  responseType?: 'arraybuffer' | 'blob' | 'json' | 'text';
  /**
   * is that with credentials
   *
   * view more:
   *
   * https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials
   */
  withCredentials?: boolean;
  /**
   * request api method type,
   *
   * @default
   * POST
   */
  method?: string;
}

Return Object

You can use this object when event return.

export interface UploadEvent {
  /**
   * upload status
   *
   * - `UploadStatus.Uploading`
   * - `UploadStatus.Completed`
   * - `UploadStatus.UploadError`
   * - `UploadStatus.FileNumError`
   */
  status: UploadStatus;
  /** what percent of current upload rate */
  percent: number;
  /** other data you want to attach */
  data?: any;
}

FileOption

export interface FileOption {
  /**
   * check upload file size
   * unit: `Byte`
   */
  size?: {
    /** the smallest bytes */
    min?: number;
    /** the biggest bytes */
    max?: number;
  }; // unit: Byte,
  /**
   * when you upload some files in once, but not throw error when have some file not in the range
   * you can set it to true, let will skip the Invalid file
   *
   * @default false
   */
  skipInvalid?: boolean;
}

FileError

You can use this enum to conclude the file select return.

export const enum FileError {
  /** when number of file Error */
  NumError,
  /** when file accept type Error */
  TypeError,
  /** when file size error */
  SizeError,
}

UploadStatus

You can use this enum to conclude the return Event.

export const enum UploadStatus {
  /** when file is uploading. */
  Uploading,
  /** when upload complete. */
  Completed,
  /** when server error. */
  UploadError,
  /** when no choice file. */
  FileNumError,
}