DEV Community

Plinio Grijalba
Plinio Grijalba

Posted on • Edited on

Carga de archivos a cloud storage por medio de firebase en angular

Contenido

Introducción

En este post se muestra como realizar la carga de archivos a cloud storage a través de firebase.

Configurar proyecto de firebase

Para configurar el proyecto de firebase se debe realizar los siguientes pasos:

  1. Acceder a firebase console y crear un nuevo proyecto.
    Crear proyecto

  2. Habilitar storage en firebase.
    Para esto en el menú lateral se encuentra la opción de storage, al ingresar a dicha opción se da click en botón de comenzar y se siguen los pasos.
    Configurar storage
    Finalizado el proceso la ventana de storage se mostrara de la siguiente manera:
    storage
    Si se desea se puede ir a cloud storage y verificar la creación de bucket
    Cloud storage
    Por ultimo se va a la pestaña de Rules y se cambia la regla para que no solicite autenticarse para realizar la carga de los archivos.
    La cual queda de la siguiente manera:
    Cambiar regla

  3. Agregar app en firebase
    En la ventana principal del proyecto se encuentra la opción de agregar app, donde muestra diferentes plataformas a seleccionar en este caso se selecciona Web y se siguen los pasos.
    Agregar app en fireabse.

Crear proyecto de Angular

Si desea puede omitir este paso y clonar el repositorio https://github.com/plinio141/test-storage-angular.
Para crear y configurar el proyecto de Angular utilizar los siguientes comandos:

 ng new test-storage-angular
 cd test-storage-angular
 ng add @angular/material
 npm i -s @angular/flex-layout 
Enter fullscreen mode Exit fullscreen mode

Posteriormente agregar al app.module lo siguiente

import {MatButtonModule} from '@angular/material/button';
import { FlexLayoutModule } from '@angular/flex-layout';

@NgModule({
  ...
  imports: [
    ...
    MatButtonModule,
    FlexLayoutModule
  ],
  ...
})
Enter fullscreen mode Exit fullscreen mode

Conectar angular con firebase

Para esto seguir los siguientes pasos:

Tomar el Json que genero firebase al registrar la aplicación y agregarlo al archivo de environment en angular de la siguiente manera:

export const environment = {
  production: false,
  firebaseConfig: {
    apiKey: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    authDomain: "XXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    databaseURL: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    projectId: "XXXXXXXXXXXXXXXXXXXXX",
    storageBucket: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    messagingSenderId: "XXXXXXXXXXXXXXXXXXXXXXXXX",
    appId: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
  }
};
Enter fullscreen mode Exit fullscreen mode

Instalar librería firebase y @angular/fire

 npm i --save firebase
 npm i @angular/fire --save
Enter fullscreen mode Exit fullscreen mode

Importar AngularFireModule, AngularFireStorageModule y environment en el app.module

import { AngularFireModule } from '@angular/fire';
import { AngularFireStorageModule } from '@angular/fire/storage';
import { environment } from '../environments/environment';
Enter fullscreen mode Exit fullscreen mode

Agregar a los imports las siguientes lineas:

AngularFireModule.initializeApp(environment.firebaseConfig),
AngularFireStorageModule,
Enter fullscreen mode Exit fullscreen mode

El app.module quedaría de la siguiente manera:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AngularFireModule } from '@angular/fire';
import { AngularFireStorageModule } from '@angular/fire/storage';
import { MatButtonModule } from '@angular/material/button';
import { FlexLayoutModule } from '@angular/flex-layout';

import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { environment } from '../environments/environment';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    MatButtonModule,
    FlexLayoutModule,
    AngularFireModule.initializeApp(environment.firebaseConfig),
    AngularFireStorageModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
Enter fullscreen mode Exit fullscreen mode

Ahora se crea una interfaz gráfica simple que contenga un input tipo file y un botón que tendrá el evento de carga del archivo en este caso se hará en el app.component.html

<section fxLayout="column" fxLayoutAlign="space-around center" fxFlex="100" fxLayoutGap="20px">
  <div class="label" fxFlex="30">Archivo</div>
  <div fxFlex="30"><input type="file" name="file"/></div>
  <div fxFlex="30">
    <button mat-flat-button color="primary">Cargar</button>
  </div>
</section>
Enter fullscreen mode Exit fullscreen mode

Si desea puede agregar los siguientes estilos:

section {
  padding: 10px;
}
.label {
  font-size: 30px;
}
Enter fullscreen mode Exit fullscreen mode

Ahora en app.component.ts se agrega una propiedad llamada file de tipo File y se crea una función que va capturar el evento de selección de una imagen.

  file: File;
Enter fullscreen mode Exit fullscreen mode
onFileSelect(event) {
    if (event.target.files.length > 0) {
      this.file = event.target.files[0];
    }
  }
Enter fullscreen mode Exit fullscreen mode

Se agrega al input file el evento change apuntando a la función anteriormente creada.

<div fxFlex="30"><input type="file" name="file" (change)="onFileSelect($event)"/></div>
Enter fullscreen mode Exit fullscreen mode

En el app.component.ts importar el AngularFireStorage y agregar una nueva función que sera la encargada de cargar los archivos.

import { AngularFireStorage } from '@angular/fire/storage';
...
 constructor(
    private storage: AngularFireStorage
 ){}
...
uploadFile() {
    const filePath = this.file.name;
    // Crea una referencia de acceso
    const fileRef = this.storage.ref(filePath);
    fileRef.put(this.file);
  }
Enter fullscreen mode Exit fullscreen mode

Agregar al botón Cargar el evento click para que cargue el archivo.

<button mat-flat-button color="primary" (click)="uploadFile()">Cargar</button>
Enter fullscreen mode Exit fullscreen mode

Con esto ya se carga un archivo a cloud storage por medio de firebase, pero visualmente no se identifica que ya fue cargado el archivo así que se va crear un mensaje de carga completa. Para esto se añade en el html lo siguiente:

<div class="label" fxFlex="30" *ngIf="completed">Archivo cargado</div>
Enter fullscreen mode Exit fullscreen mode

Además, en el app.component.ts se agrega una propiedad para mostrar y ocultar el mensaje de carga completa, de igual manera se debe modificar la función de uploadFile para actualizar la propiedad completed cuando se termine de cargar el archivo.

uploadFile() {
    this.completed = false;
    const filePath = this.file.name;
    // Crea una referencia de acceso
    const fileRef = this.storage.ref(filePath);
    fileRef.put(this.file).then(() => {
      this.completed = true;
    });
  }
Enter fullscreen mode Exit fullscreen mode

Por ultimo se puede añadir una barra de carga. Para esto se va hacer uso del componente mat-progress-bar de angular material para lo cual se debe importar en el app.module.

...
import { MatProgressBarModule } from '@angular/material/progress-bar';
...
imports: [
    ...
    MatProgressBarModule,
    ...
  ],
...
Enter fullscreen mode Exit fullscreen mode

Para usar el componente se añade al html de la siguiente manera:

<mat-progress-bar *ngIf="!completed" mode="determinate" value="uploadPercent | async"></mat-progress-bar>
Enter fullscreen mode Exit fullscreen mode

En el app.component se añade la propiedad uploadPercent y se actualiza la función uploadFile para esto se debe importar finalize y Observable para un funcionamiento correcto.

import { finalize } from 'rxjs/operators';
import { Observable } from 'rxjs';
...
uploadFile() {
    this.completed = false;
    const filePath = this.file.name;
    const task = this.storage.upload(filePath, this.file);

    this.uploadPercent = task.percentageChanges();

    task.snapshotChanges().pipe(
      finalize(() => {
        this.completed = true;
      })
    )
    .subscribe();
  }
```


Los archivos quedan de la siguiente manera:
app.module.ts


```javascript
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AngularFireModule } from '@angular/fire';
import { AngularFireStorageModule } from '@angular/fire/storage';
import { MatButtonModule } from '@angular/material/button';
import { FlexLayoutModule } from '@angular/flex-layout';
import { MatProgressBarModule } from '@angular/material/progress-bar';

import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { environment } from '../environments/environment';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    MatButtonModule,
    MatProgressBarModule,
    FlexLayoutModule,
    AngularFireModule.initializeApp(environment.firebaseConfig),
    AngularFireStorageModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
```


app.component.ts


```javascript
import { Component } from '@angular/core';
import { AngularFireStorage } from '@angular/fire/storage';
import { finalize } from 'rxjs/operators';
import { Observable } from 'rxjs';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  file: File;
  completed = false;
  uploadPercent: Observable<number>;

  constructor(
    private storage: AngularFireStorage
  ){}

  uploadFile() {
    this.completed = false;
    const filePath = this.file.name;
    const task = this.storage.upload(filePath, this.file);

    this.uploadPercent = task.percentageChanges();

    task.snapshotChanges().pipe(
      finalize(() => {
        this.completed = true;
      })
    )
    .subscribe();
  }

  onFileSelect(event) {
    if (event.target.files.length > 0) {
      this.file = event.target.files[0];
    }
  }

}
```


app.component.html


```html
<section fxLayout="column" fxLayoutAlign="space-around center" fxFlex="100" fxLayoutGap="20px">
  <div class="label" fxFlex="30">Archivo</div>
  <div fxFlex="30"><input type="file" name="file" (change)="onFileSelect($event)"/></div>
  <div fxFlex="30">
    <button mat-flat-button color="primary" (click)="uploadFile()">Cargar</button>
  </div>
  <mat-progress-bar mode="determinate" [value]="uploadPercent | async"></mat-progress-bar>
  <div class="label" fxFlex="30" *ngIf="completed">Archivo cargado</div>
</section>
```



Este código se encuentra en https://github.com/plinio141/test-storage-angular

Enter fullscreen mode Exit fullscreen mode

Top comments (0)