Angular загрузка не выполняется правильно - PullRequest
0 голосов
/ 18 апреля 2020

Я пытаюсь создать форму для загрузки, основанную на этой статье:

https://malcoded.com/posts/angular-file-upload-component-with-express/

Я использую angular 9 и ngx- bootstrap и я не использую диалог или angular материал. Итак, я взимал плату за загрузку следующим образом:

import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';
import {
  HttpClient,
  HttpRequest,
  HttpEventType,
  HttpResponse,
} from '@angular/common/http';

import { environment } from '@environments/environment';

@Injectable({
  providedIn: 'root',
})
export class UploadService {
  private url: string = `${environment.apiUrl}/halls/file`;

  constructor(private http: HttpClient) {}

  public upload(
    files: Set<File>
  ): { [key: string]: { progress: Observable<number> } } {
    // this will be the our resulting map
    const status: { [key: string]: { progress: Observable<number> } } = {};

    files.forEach((file) => {
      // create a new multipart-form for every file
      const formData: FormData = new FormData();
      formData.append('file', file, file.name);

      // create a http-post request and pass the form
      // tell it to report the upload progress
      const req = new HttpRequest('POST', this.url, formData, {
        reportProgress: true,
      });

      // create a new progress-subject for every file
      const progress = new Subject<number>();

      // send the http-request and subscribe for progress-updates
      this.http.request(req).subscribe((event) => {
        if (event.type === HttpEventType.UploadProgress) {
          // calculate the progress percentage
          const percentDone = Math.round((100 * event.loaded) / event.total);

          // pass the percentage into the progress-stream
          progress.next(percentDone);
        } else if (event instanceof HttpResponse) {
          // Close the progress-stream if we get an answer form the API
          // The upload is complete
          progress.complete();
        }
      });

      // Save every progress-observable in a map of all observables
      status[file.name] = {
        progress: progress.asObservable(),
      };
    });

    // return the map of progress.observables
    return status;
  }
}

Единственное, что я изменил в службе - это URL (по понятным причинам). Затем я создал компонент для использования этого сервиса:

import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
import { Observable, forkJoin } from 'rxjs';

import { UploadService } from '@services';
import { Screenshot } from '../_core/models/screenshot';

@Component({
  selector: 'app-screenshots-save',
  templateUrl: './screenshots-save.component.html',
  styleUrls: ['./screenshots-save.component.scss'],
})
export class ScreenshotsSaveComponent implements OnInit {
  @ViewChild('file', { static: false }) file: ElementRef;

  public screenshots: Screenshot[] = [];
  public files: Set<File> = new Set();
  public urls: string[] = [];
  public progress: { [key: string]: { progress: Observable<number> } } = {};
  public uploading: boolean = false;
  public uploadSuccessful: boolean = false;

  constructor(private uploadService: UploadService) {}

  ngOnInit(): void {}

  onFilesAdded(event: any): void {
    const files: { [key: string]: File } = this.file.nativeElement.files;
    for (let key in files) {
      if (!isNaN(parseInt(key))) {
        var f = files[key];
        let reader = new FileReader();

        reader.onload = (e: any) => {
          this.urls.push(e.target.result);
        };

        this.files.add(f);
        reader.readAsDataURL(f);
      }
    }
  }

  addFiles(): void {
    this.file.nativeElement.click();
  }

  upload(): void {
    this.uploading = true;
    this.progress = this.uploadService.upload(this.files);

    let allProgressObservables = [];
    for (let key in this.progress) {
      allProgressObservables.push(this.progress[key].progress);
    }

    forkJoin(allProgressObservables).subscribe(() => {
      this.uploadSuccessful = true;
      this.uploading = false;
    });
  }

  clear(): void {
    this.files = new Set();
    this.urls = [];
    this.progress = {};
    this.uploading = false;
    this.uploadSuccessful = false;
  }
}

Это немного отличается от его, потому что он не использует диалог, но большинство из них то же самое. Основная часть - это метод upload. Вы можете видеть, что я прикрепляю прогресс к службе загрузки в этой строке this.progress = this.uploadService.upload(this.files);.

В моем html я сделал это:

<form>
    <div class="d-none">
        <label>Screenshots</label>
        <input #file class="form-control-file" type="file" multiple accept=".jpg,.png"
            (change)="onFilesAdded($event)" />
    </div>

    <div class="form-group">
        <button class="btn btn-dark mr-2" type="button" (click)="addFiles()">Add
            screenshot(s)</button>
        <button class="btn btn-primary mr-2" type="button" [disabled]="!files.size"
            (click)="upload()">Upload</button>
        <button class="btn btn-danger" type="button" [disabled]="!files.size"
            (click)="clear()">Clear</button>
    </div>
</form>

<div class="row">
    <div class="col-md-4" *ngFor="let file of files; let i = index">
        <div class="card mb-4">
            <img class="card-img-top" [src]="urls[i]" [alt]="file.name">
            <div class="card-body">
                <h5 class="card-title">{{ file.name }}</h5>

                <progressbar [value]="progress[file.name]?.progress | async" [striped]="true"
                    [animate]="true">
                </progressbar>
            </div>
        </div>
    </div>
</div>

Как вы можете видеть Я привязываю прогресс к индикатору прогресса ngx- bootstrap. Когда я добавляю свои файлы, это показывает как 0, который это должно. Но когда я нажимаю кнопку загрузки, все файлы показывают прогресс 100, хотя на самом деле загрузка еще не завершена. Задержка перед переходом к следующему экрану означает, что индикатор выполнения не меняется, как я ожидал. Это либо 0, либо 100 вместо того, чтобы быть инкрементным.

Может кто-нибудь определить, что я делаю неправильно?

...