### File

`src/lib/file-upload.method.ts`

### Index

###### Properties

- Protected _document
- Protected _fileInput
- Public progress$

###### Methods

- Protected addInputToDom
- Public call
- Protected getDocument
- Protected handleFileInputChange
- Protected readFile
- Protected removeInputFromDom
- Public setDocument

###### Accessors

- document

### Methods

Protected addInputToDom
`addInputToDom(accept: string)`
Defined in src/lib/file-upload.method.ts:113

Parameters :

Name | Type | Optional
accept | `string` | No

Returns : `HTMLInputElement`

Public call
`call(parameters?: FileUploadMethodParameters)`
Defined in src/lib/file-upload.method.ts:37

Parameters :

Name | Type | Optional
parameters | `FileUploadMethodParameters` | Yes

Returns : `Promise<File | null>`

Protected getDocument
`getDocument()`
Defined in src/lib/file-upload.method.ts:122
Returns : `Document`

Protected handleFileInputChange
`handleFileInputChange(event: any)`
Defined in src/lib/file-upload.method.ts:62

Parameters :

Name | Type | Optional
event | `any` | No

Returns : `File | null`

Protected readFile
`readFile(file: File)`
Defined in src/lib/file-upload.method.ts:84

Parameters :

Name | Type | Optional
file | `File` | No

Returns : `Promise<File>`

Protected removeInputFromDom
`removeInputFromDom()`
Defined in src/lib/file-upload.method.ts:77
Returns : `void`

Public setDocument
`setDocument(document: Document)`
Defined in src/lib/file-upload.method.ts:58

Parameters :

Name | Type | Optional
document | `Document` | No

Returns : `void`

### Properties

Protected _document
Type : `Document | null`
Default value : `null`
Defined in src/lib/file-upload.method.ts:28

Protected _fileInput
Type : `HTMLInputElement | null`
Default value : `null`
Defined in src/lib/file-upload.method.ts:26

Public progress$
Type : `Subject<number>`
Default value : `new Subject<number>()`
Defined in src/lib/file-upload.method.ts:24

### Accessors

document
get `document()`
Defined in src/lib/file-upload.method.ts:30

    import { Injectable } from '@angular/core';
    import { Method } from '@rxap/pattern';
    import {
      firstValueFrom,
      fromEvent,
      of,
      race,
      Subject,
    } from 'rxjs';
    import {
      map,
      switchMap,
      take,
    } from 'rxjs/operators';

    export interface FileUploadMethodParameters {
      accept?: string;
      fileInput?: HTMLInputElement;
    }

    @Injectable()
    export class FileUploadMethod implements Method<File | null, FileUploadMethodParameters> {

      public progress$: Subject<number> = new Subject<number>();

      protected _fileInput: HTMLInputElement | null = null;

      protected _document: Document | null = null;

      protected get document(): Document {
        if (!this._document) {
          this._document = this.getDocument();
        }
        return this._document;
      }

      public call(parameters?: FileUploadMethodParameters): Promise<File | null> {
        const accept = parameters?.accept ?? '**/**';
        const fileInput = parameters?.fileInput ?? this.addInputToDom(accept);
        fileInput.setAttribute('accept', accept);

        const change$ = fromEvent(fileInput, 'change').pipe(
          map(event => this.handleFileInputChange(event)),
          switchMap(file => file ? this.readFile(file) : of(null)),
          take(1),
        );

        const cancel$ = fromEvent(this.document.body, 'focus').pipe(take(1), map(() => null));

        fileInput.click();

        return firstValueFrom(race(
          change$,
          cancel$,
        ));
      }

      public setDocument(document: Document) {
        this._document = document;
      }

      protected handleFileInputChange(event: any): File | null {
        this.removeInputFromDom();
        const files: { [key: string]: File } = event?.target?.files as any ?? {};
        if (Object.keys(files).length !== 1) {
          throw new Error('File upload failed');
        }
        let file: File | null = null;
        for (const key in files) {
          if (!isNaN(parseInt(key, 10))) {
            file = files[key];
          }
        }
        return file;
      }

      protected removeInputFromDom(): void {
        if (this._fileInput) {
          this.document.body.removeChild(this._fileInput);
        }
        this._fileInput = null;
      }

      protected readFile(file: File): Promise<File> {
        const reader = new FileReader();

        const loadFile$ = fromEvent<any>(reader, 'load').pipe(
          map(event => new File(
            [ event.target.result ],
            file.name,
            {
              type: file.type,
              lastModified: file.lastModified,
            },
          )),
          take(1),
        );

        fromEvent(reader, 'progress').pipe(
          map((progress: Event) => {
            if (progress instanceof ProgressEvent) {
              return progress.loaded / progress.total * 100;
            }
            throw new Error('The progress event is not an instance of ProgressEvent');
          }),
        ).subscribe(this.progress$);

        reader.readAsArrayBuffer(file);

        return firstValueFrom(loadFile$);
      }

      protected addInputToDom(accept: string): HTMLInputElement {
        const fileInput = this.document.createElement('input');
        fileInput.setAttribute('type', 'file');
        fileInput.setAttribute('style', 'display: none');
        fileInput.setAttribute('accept', accept);
        this.document.body.appendChild(fileInput);
        return this._fileInput = fileInput;
      }

      protected getDocument(): Document {
        return window.document;
      }

    }

# results matching ""

# No results matching ""