npm package: @lukana/file-uploader
Description: ```html     <lukana-file-uploader [multiple]="true" language="pl"></lukana-file-uploader>     <lukana-file-uploader-progress></lukana-file-uploader-progress> ```
Latest version: 2.0.1

```html
    <lukana-file-uploader [multiple]="true" language="pl"></lukana-file-uploader>
    <lukana-file-uploader-progress></lukana-file-uploader-progress>
```

# Language support

It is based on [bootstrap's](https://getbootstrap.com/docs/4.1/components/forms/#translating-or-customizing-the-strings) `file input` so You have to provide in scss:

```scss
$custom-file-text: (
    en: "Browse",
    pl: "Wybierz"
);

@import "bootstrap/scss/bootstrap";
```

# Built-in api service

You can use built-in api service which has simple config:

```typescript
@NgModule({
  imports: [
    ...
    FileUploaderModule.forRoot({
        apiUrl: 'http://url.com/',
        apiFileParam: 'file',
    }),
  ],
  providers: [
    {provide: FileUploaderService, useClass: FileUploaderService}
  ],
})
```

# Custom upload service

Provide service in `forRoot`

```typescript
@NgModule({
  imports: [
    ...
    FileUploaderModule.forRoot(),
  ],
  providers: [
    {provide: FileUploaderService, useClass: MyFileUploaderService}
  ],
})
```

This is default service

```typescript
import {Injectable} from '@angular/core';
import {HttpClient, HttpEventType} from '@angular/common/http';
import {Subject} from 'rxjs';

import {FileUploaderServiceInterface} from '@lukana/file-uploader';
import {FilesUploadingModel} from '@lukana/file-uploader';

const RESET_FILES_UPLOADING: FilesUploadingModel = {
  files: [],
  total: {
    loaded: 0,
    progress: 0,
    total: 0
  },
  completed: false,
  uploading: false,
};

@Injectable()
export class MyFileUploaderService implements FileUploaderServiceInterface {
  protected apiUrl = 'http://url.com/';
  protected apiFileParam = 'file';
  protected _filesUploadingSubject: Subject<FilesUploadingModel> = new Subject();
  protected _filesUploading: FilesUploadingModel = RESET_FILES_UPLOADING;
  filesUploading$ = this._filesUploadingSubject.asObservable();

  constructor(protected http: HttpClient) {
  }

  startUpload(files: FileList): void {
    const filesAlreadyUploading = this._filesUploading.files.length;
    for (let i = 0; i < files.length; i++) {
      const file = files[i];
      this._filesUploading.files.push({
        name: file.name,
        progress: 0,
        total: 0,
        loaded: 0,
        completed: false,
        response: null,
      });
    }
    this._filesUploading.uploading = true;
    this._filesUploading.completed = false;
    this._filesUploadingSubject.next(this._filesUploading);
    for (let index = 0; index < files.length; index++) {
      this._uploadFile(files[index], index + filesAlreadyUploading);
    }
  }

  clear() {
    this._filesUploading = RESET_FILES_UPLOADING;
  }

  protected _uploadFile(file: File, index: number) {
    this._getUploadingMethod(file)
      .subscribe(event => {
        if (event.type === HttpEventType.UploadProgress) {
          const progress = Math.round(event.loaded / event.total * 100);
          this._filesUploading.files[index] = {
            ...this._filesUploading.files[index],
            progress: progress,
            total: event.total,
            loaded: event.loaded,
            completed: false,
          };
          this._calculateTotal();
          this._filesUploadingSubject.next(
            {...this._filesUploading}
          );
        } else if (event.type === HttpEventType.Response) {
          this._filesUploading.files[index] = {
            ...this._filesUploading.files[index],
            progress: 100,
            completed: true,
            response: event.body
          };
          let all = true;
          this._filesUploading.files.forEach(item => {
            if (!item.completed) {
              all = false;
            }
          });
          if (all) {
            this._filesUploading.completed = true;
            this._filesUploading.uploading = false;
          }
          this._filesUploadingSubject.next(
            {...this._filesUploading}
          );
        }
      });
  }

  protected _getUploadingMethod(file: File) {
    const fd = new FormData();
    fd.append(this.apiFileParam, file, file.name);
    return this.http.post(this.apiUrl, fd, {
      reportProgress: true,
      observe: 'events',
    });
  }

  protected _calculateTotal() {
    let total = 0;
    let loaded = 0;
    this._filesUploading.files.forEach(item => {
      total += item.total;
      loaded += item.loaded;
    });
    this._filesUploading.total = {
      total,
      loaded,
      progress: Math.round(loaded / total * 100)
    };
  }
}
```