
En este tutorial vamos a realizar el frontend en Angular para subir múltiples/varios archivos, se utiliza Angular Material para el aspecto de la aplicación. Si quieres ver el backend de esta aplicación da clic aqui.
El resultado que vamos a obtener con este proyecto en la parte Front en Angular es este:

Tabla de Contenido
Creación y configuración del proyecto en Angular
Abrimos la consola de comandos y escribimos lo siguiente
ng new UploadFilesFront ? Would you like to add Angular routing? Yes ? Which stylesheet format would you like to use? CSS
Nos ubicamos en la carpeta de nuestro proyecto y creamos un componente
ng g c components/upload-files
Luego generamos un servicio:
ng g s services/upload-files
Añadimos Angular Material con el siguiente comando
ng add @angular/material
Deberías tener una estructura como la siguiente

- Component upload-files.component –> Componente donde vamos a crear el html que vamos a mostrar.
- Services upload-files.component –> Servicio en el cual vamos a hacer la llamada a los endpoints o Apis Rest para subir archivos, obtenerlos y borrarlos
Importando los módulos en app.module
Nos ubicamos en el archivo app.module.ts para hacer la importación de los módulos necesarios del proyecto.
import { HttpClientModule } from '@angular/common/http'; import {MatProgressBarModule} from '@angular/material/progress-bar'; import {MatButtonModule} from '@angular/material/button'; import {MatCardModule} from '@angular/material/card'; import {MatIconModule} from '@angular/material/icon'; import {MatGridListModule} from '@angular/material/grid-list';
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { UploadFilesComponent } from './components/upload-files/upload-files.component'; import { HttpClientModule } from '@angular/common/http'; import {MatProgressBarModule} from '@angular/material/progress-bar'; import {MatButtonModule} from '@angular/material/button'; import {MatCardModule} from '@angular/material/card'; import {MatIconModule} from '@angular/material/icon'; @NgModule({ declarations: [ AppComponent, UploadFilesComponent ], imports: [ BrowserModule, AppRoutingModule, HttpClientModule, BrowserAnimationsModule, MatProgressBarModule, MatButtonModule, MatCardModule, MatIconModule, ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
- HttpClientModule –> Este módulo se utiliza para poder realizar las peticiones a las Apis Rest.
- MatProgressBarModule –> Módulo para utilizar el progress bar de Angular Material
- MatButtonModule –> Módulo para utilizar botones de Angular Material
- MatCardModule –> Módulo para utilizar el componente card de Angular Material
- MatIconModule –> Módulo para utilizar los iconos de Angular Material
Añadiendo la URL Base de los endpoints
Nos dirigimos al archivo enviroment.ts que se encuentra en la carpeta enviroments/enviroment.ts donde vamos a crear una variable llamada baseUrl donde vamos a almacenar la url base de nuestros endpoints.
export const environment = { production: false, baseUrl: 'http://localhost:8080' };
Creación del servicio para subir, obtener y eliminar varios archivos
Nos ubicamos en el archivo upload-files.service.ts
import { Injectable } from '@angular/core'; import { environment } from '../../environments/environment'; import { HttpClient, HttpRequest, HttpEvent,HttpParams} from '@angular/common/http'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class UploadFilesService { //Url obtenida de la variable de enviroments baseUrl = environment.baseUrl; //Inyeccion de HttpClient constructor(private http: HttpClient) { } //Metodo que envia los archivos al endpoint /upload upload(file: File): Observable<HttpEvent<any>>{ const formData: FormData = new FormData(); formData.append('files', file); const req = new HttpRequest('POST', `${this.baseUrl}/upload`, formData, { reportProgress: true, responseType: 'json' }); return this.http.request(req); } //Metodo para Obtener los archivos getFiles(){ return this.http.get(`${this.baseUrl}/files`); } //Metodo para borrar los archivos deleteFile(filename: string){ return this.http.get(`${this.baseUrl}/delete/${filename}`); } }
- FormData –> Es una estructura de datos que almacena parejas clave – valor. Se usa para construir el objeto que vamos a mandar a la Api.
- ReportProgress –> Se pone en true para mostrar el progreso de la petición HTTP
- Utilizamos peticiones POST y GET
Creación del component.ts
Nos dirigimos al componente previamente creado upload-files.component.ts
Primero importamos el servicio previamente creado, Observable, HttpEventType y HttpResponse
import { Component, OnInit } from '@angular/core'; import { UploadFilesService } from '../../services/upload-files.service'; import { Observable } from 'rxjs'; import { HttpEventType, HttpResponse } from '@angular/common/http';
Lo siguiente es crear estas variables:
//Lista de archivos seleccionados selectedFiles: FileList; //Es el array que contiene los items para mostrar el progreso de subida de cada archivo progressInfo = [] //Mensaje que almacena la respuesta de las Apis message = ''; //Nombre del archivo para usarlo posteriormente en la vista html fileName = ""; fileInfos: Observable<any>;
Inyectamos el servicio al constructor:
constructor(private uploadFilesService: UploadFilesService) { }
Creamos un método que permita obtener los archivos seleccionados:
selectFiles(event) { this.progressInfo = []; //Validación para obtener el nombre del archivo si es uno solo //En caso de que sea >1 asigna a fileName length event.target.files.length == 1 ? this.fileName = event.target.files[0].name : this.fileName = event.target.files.length + " archivos"; this.selectedFiles = event.target.files; }
Creamos un método que recorra uno por uno los archivos seleccionados para ir llamando el método de subida (upload).
uploadFiles() { this.message = ''; for (let i = 0; i < this.selectedFiles.length; i++) { this.upload(i, this.selectedFiles[i]); } }
Creación del método upload()
upload(index, file) { this.progressInfo[index] = { value: 0, fileName: file.name }; this.uploadFilesService.upload(file).subscribe( event => { if (event.type === HttpEventType.UploadProgress) { this.progressInfo[index].value = Math.round(100 * event.loaded / event.total); } else if (event instanceof HttpResponse) { this.fileInfos = this.uploadFilesService.getFiles(); } }, err => { this.progressInfo[index].value = 0; this.message = 'No se puede subir el archivo ' + file.name; }); }
- index –> Índice del archivo actual
- progressInfo –> Valor del progreso actual de la subida del archivo, el cual vamos a pasar al matprogressbar
El siguiente método que creamos es para borrar un archivo por nombre:
deleteFile(filename: string) { this.uploadFilesService.deleteFile(filename).subscribe(res => { this.message = res['message']; this.fileInfos = this.uploadFilesService.getFiles(); }); }
En el ngOnInit hacemos la llamada al método de obtener los archivos:
ngOnInit(): void { this.fileInfos = this.uploadFilesService.getFiles(); }
La clase completa se ve de esta manera:
import { Component, OnInit } from '@angular/core'; import { UploadFilesService } from '../../services/upload-files.service'; import { Observable } from 'rxjs'; import { HttpEventType, HttpResponse } from '@angular/common/http'; @Component({ selector: 'app-upload-files', templateUrl: './upload-files.component.html', styleUrls: ['./upload-files.component.css'] }) export class UploadFilesComponent implements OnInit { selectedFiles: FileList; //Es el array que contiene los items para mostrar el progreso de subida de cada archivo progressInfo = [] message = ''; fileName = ""; fileInfos: Observable<any>; constructor(private uploadFilesService: UploadFilesService) { } ngOnInit(): void { this.fileInfos = this.uploadFilesService.getFiles(); } selectFiles(event) { this.progressInfo = []; event.target.files.length == 1 ? this.fileName = event.target.files[0].name : this.fileName = event.target.files.length + " archivos"; this.selectedFiles = event.target.files; } uploadFiles() { this.message = ''; for (let i = 0; i < this.selectedFiles.length; i++) { this.upload(i, this.selectedFiles[i]); } } upload(index, file) { this.progressInfo[index] = { value: 0, fileName: file.name }; this.uploadFilesService.upload(file).subscribe( event => { if (event.type === HttpEventType.UploadProgress) { this.progressInfo[index].value = Math.round(100 * event.loaded / event.total); } else if (event instanceof HttpResponse) { this.fileInfos = this.uploadFilesService.getFiles(); } }, err => { this.progressInfo[index].value = 0; this.message = 'No se puede subir el archivo ' + file.name; }); } deleteFile(filename: string) { this.uploadFilesService.deleteFile(filename).subscribe(res => { this.message = res['message']; this.fileInfos = this.uploadFilesService.getFiles(); }); } }
Creación del component.html
<div id="wrap"> <mat-card id="box1"> <div mode="buffer" *ngFor="let progress of progressInfo"> <span>{{progress.fileName}}</span> <span>{{progress.value}}%</span> <div id="progressbar"> <mat-progress-bar mode="buffer" value={{progress.value}}> </mat-progress-bar> </div> </div> </mat-card> <div id="box2"> <button id="selectButton" mat-raised-button (click)="fileInput.click()">Select File to Upload</button> <input #fileInput type="file" hidden multiple (change)="selectFiles($event)" /> <span *ngIf="fileName">{{fileName}}</span> <button id="uploadButton" mat-raised-button *ngIf="selectedFiles" [disabled]="!selectedFiles" (click)="uploadFiles()"> Subir Archivos </button> </div> <div id="box3"> <span>{{message}}</span> </div> <div id="box4"> <mat-card> <mat-card-header> <mat-card-title>Lista de Archivos</mat-card-title> </mat-card-header> <mat-card-content> <ul> <li *ngFor="let file of fileInfos | async"> <a href="{{file.url}}">{{file.name}}</a> <mat-icon (click)="deleteFile(file.name)">delete</mat-icon> </li> </ul> </mat-card-content> </mat-card> </div> </div>
Estilos del Component.html
#wrap{ display: block; } #box1, #box2, #box3, #box4{ display: block; width: 50%; margin-left: auto; margin-right: auto; margin-top: 10px; margin-bottom: 10px; text-align: center; } #box1{ text-align: center; border: 1px solid gray; height: 250px; overflow: auto; } #progressbar{ text-align: center; height: 20px; padding: 10px; } #box1 span{ margin-left: 10px; } #box2 span{ margin-left: 10px; margin-right: 10px; } #box2 #selectButton{ background-color: rgb(1, 155, 1); } #box2 #uploadButton{ background-color: rgb(26, 26, 160); } #box3{ color: red; } #box4 ul{ list-style: none; } #box4 ul li{ display: flex; justify-content: space-between; align-items: center; } #box4 ul li a{ text-decoration: none; color: white; margin-right: 20px; }
Añadiendo el componente a app.component.html
<div id="titulo"> <h1>Subir múltiples archivos Angular y Java</h1> </div> <div> <app-upload-files></app-upload-files> <router-outlet></router-outlet> </div>
#titulo{ display: block; width: 100%; margin-left: auto; margin-right: auto; height: 50px; line-height: 50px; padding: 20px; text-align: center; }
Corriendo la aplicación
Para correr la aplicación ejecutamos el comando ng serve, abrimos el navegador en el puerto que corresponda


El repositorio de este proyecto por si tienes dudas:
Este tutorial lo encuentras en video en mi canal de YouTube:
Proyecto Backend Java Spring Boot
Da clic en el siguiente link para encontrar el tutorial de como hacer el backend de esta aplicación
Buen día he seguido tu blog y son muy buenos tutoriales.
Una pregunta con respecto el front end, a la hora de desplegar los archivos que se encuentran en el back end. Se despliegan de manera correcta. pero a la hora de refrescar la página (localhost) se pierden en pantalla. ¿Como le puedo hacer para que se queden de manera estática la lista de los archivos. Para que a la hora de recargar o ingresar a la aplicación me muestre la lista de archivos que ya están cargados en e backend.
De antemano gracias por el apoyo.