Загрузка файлов

Загрузка файлов — одна из часто встречающихся задач при разработке веб-приложений. Angular предоставляет набор инструментов и подходов, позволяющих реализовать эту функциональность эффективно и безопасно. Основные компоненты процесса загрузки включают работу с формами, обработку событий, отправку данных на сервер и управление прогрессом.


HTML-форма для выбора файла

Для начала создается форма с элементом <input type="file">. Angular позволяет использовать двустороннюю привязку данных и связывать выбранный файл с переменной в компоненте:

<form (ngSubmit)="uploadFile()">
  <input type="file" (change)="onFileSelected($event)" />
  <button type="submit">Загрузить</button>
</form>

Ключевой момент — событие change, которое срабатывает при выборе файла. Оно позволяет получить объект File, который можно отправить на сервер.


Обработка выбранного файла

В компоненте создается метод для обработки события выбора файла:

import { Component } from '@angular/core';

@Component({
  selector: 'app-file-upload',
  templateUrl: './file-upload.component.html'
})
export class FileUploadComponent {
  selectedFile: File | null = null;

  onFileSelected(event: Event): void {
    const input = event.target as HTMLInputElement;
    if (input.files && input.files.length > 0) {
      this.selectedFile = input.files[0];
    }
  }
}

Особенности:

  • Тип File содержит имя, размер, тип и содержимое файла.
  • Проверка input.files && input.files.length > 0 предотвращает ошибки при отсутствии выбранного файла.
  • Можно добавить фильтрацию по типу и размеру файлов для безопасности и удобства пользователя.

Отправка файла на сервер

Для загрузки файла используется объект FormData, который позволяет передавать бинарные данные через HTTP-запрос:

import { HttpClient, HttpEvent, HttpEventType } from '@angular/common/http';
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class FileUploadService {
  constructor(private http: HttpClient) {}

  upload(file: File) {
    const formData = new FormData();
    formData.append('file', file, file.name);

    return this.http.post('/api/upload', formData, {
      reportProgress: true,
      observe: 'events'
    });
  }
}

Метод post принимает FormData и позволяет отслеживать прогресс загрузки через параметр observe: 'events'.


Отслеживание прогресса загрузки

Для информирования пользователя о состоянии загрузки удобно использовать обработку событий HttpEvent:

uploadFile(): void {
  if (!this.selectedFile) return;

  this.fileUploadService.upload(this.selectedFile).subscribe(event => {
    if (event.type === HttpEventType.UploadProgress && event.total) {
      const progress = Math.round((100 * event.loaded) / event.total);
      console.log(`Прогресс: ${progress}%`);
    } else if (event.type === HttpEventType.Response) {
      console.log('Файл успешно загружен');
    }
  });
}

Особенности:

  • HttpEventType.UploadProgress возвращает loaded и total для вычисления процента загрузки.
  • HttpEventType.Response сигнализирует об успешном завершении операции.
  • Можно использовать BehaviorSubject для отображения прогресса в пользовательском интерфейсе.

Множественная загрузка файлов

Angular позволяет обрабатывать несколько файлов одновременно, изменяя атрибут multiple у <input> и расширяя логику обработки:

<input type="file" (change)="onFilesSelected($event)" multiple />
selectedFiles: File[] = [];

onFilesSelected(event: Event): void {
  const input = event.target as HTMLInputElement;
  if (input.files) {
    this.selectedFiles = Array.from(input.files);
  }
}

Для отправки на сервер можно итерировать массив файлов и формировать FormData для каждого или объединять их в один запрос.


Валидация файлов

Важно проверять размер и тип файлов перед отправкой:

const allowedTypes = ['image/png', 'image/jpeg'];
const maxSize = 5 * 1024 * 1024; // 5 МБ

validateFile(file: File): boolean {
  return allowedTypes.includes(file.type) && file.size <= maxSize;
}

Эта проверка повышает безопасность и предотвращает ошибки на сервере.


Drag-and-Drop загрузка

Для более современного интерфейса можно реализовать drag-and-drop:

<div
  class="drop-zone"
  (drop)="onDrop($event)"
  (dragover)="onDragOver($event)"
>
  Перетащите файлы сюда
</div>
onDragOver(event: DragEvent) {
  event.preventDefault();
}

onDrop(event: DragEvent) {
  event.preventDefault();
  if (event.dataTransfer?.files) {
    this.selectedFiles = Array.from(event.dataTransfer.files);
  }
}

Особенности:

  • Метод preventDefault() нужен для корректного поведения браузера.
  • Drag-and-drop поддерживает множественные файлы и может комбинироваться с обычной формой выбора.

Настройка HTTP-запроса и обработка ошибок

Важно обрабатывать ошибки сервера и сетевые сбои:

this.fileUploadService.upload(this.selectedFile).subscribe({
  next: event => { /* обработка прогресса */ },
  error: err => console.error('Ошибка загрузки:', err),
  complete: () => console.log('Загрузка завершена')
});

Можно использовать catchError и retry из RxJS для более надежной обработки:

import { catchError, retry } from 'rxjs/operators';

Дополнительные возможности

  • Преобразование файлов перед отправкой (например, изменение размеров изображений).
  • Поддержка потоковой загрузки больших файлов через chunked upload.
  • Интеграция с облачными хранилищами (AWS S3, Google Cloud Storage) с предподписанными URL.

Эта структура обеспечивает надежную и гибкую систему загрузки файлов в Angular-приложениях, охватывая основные сценарии: выбор файла, валидация, прогресс, множественные файлы и drag-and-drop.