Tutorial de Angular 6: Nuevas funciones con nueva potencia
Publicado: 2022-03-11¡Angular 6 está disponible! Los cambios más destacados están en su CLI y en cómo se inyectan los servicios. Si está buscando escribir su primera aplicación Angular 6, o aplicación Angular/Firebase, en este tutorial, repasaremos los pasos básicos de la configuración inicial y crearemos una pequeña aplicación de diario.
Angular 6: Los fundamentos
Si nunca has usado Angular antes, déjame darte una breve descripción y cómo funciona.
Angular es un marco de JavaScript diseñado para admitir la creación de aplicaciones de una sola página (SPA) tanto para escritorio como para dispositivos móviles.
El marco incluye un conjunto completo de directivas y módulos que le permiten implementar fácilmente algunos de los escenarios más comunes para una aplicación web, como navegación, autorización, formularios e informes. También viene con todos los paquetes necesarios para agregar pruebas usando el marco Jasmine y ejecutarlas usando los corredores de prueba Karma o Protractor.
La arquitectura angular se basa en componentes, plantillas, directivas y servicios. Proporciona un mecanismo de inyección de dependencia integrado para sus servicios, así como un enlace de datos bidireccional para conectar sus vistas con el código de su componente.
Angular usa TypeScript, un superconjunto escrito de JS, y hará que algunas cosas sean más fáciles, especialmente si proviene de un entorno de lenguaje escrito.
Angular 6: nuevas características
Un breve resumen de las nuevas características en Angular 6:
- Una política de sincronización de los números de versión principales para los paquetes de framework (
@angular/core
,@angular/common
,@angular/compiler
, etc.), CLI, Material y CDK. Esto ayudará a que la compatibilidad cruzada sea más clara en el futuro: con un vistazo rápido al número de versión, puede saber si los paquetes clave son compatibles entre sí. - Nuevos comandos
ng
CLI:-
ng update
para actualizar las versiones de los paquetes de forma inteligente, actualizando las versiones de las dependencias y manteniéndolas sincronizadas. (Por ejemplo, cuando se ejecutang update @angular/core
todos los marcos se actualizarán, así como RxJS). También ejecutará esquemas si el paquete los incluye. (Si una versión más reciente incluye cambios importantes que requieren cambios en el código, el esquema actualizará su código por usted). -
ng add
para agregar nuevos paquetes (y ejecutar scripts, si corresponde)
-
- Los servicios ahora hacen referencia a los módulos que los proporcionarán, en lugar de que los módulos hagan referencia a los servicios, como solían ser.
Como ejemplo de lo que significa este último cambio, donde solía verse su código:
@NgModule({ // ... providers: [MyService] })
…con este cambio particular en Angular 6, se verá así:
@Injectabe({ providedIn: 'root', })
Estos se denominan proveedores que se pueden sacudir en el árbol y permiten que el compilador elimine los servicios no referenciados, lo que da como resultado paquetes de menor tamaño.
Angular 6 CLI
La interfaz de línea de comandos ng
es una pieza muy importante de Angular y le permite moverse más rápido al codificar su aplicación.
Con la CLI, puede montar la configuración inicial de su aplicación muy fácilmente, generar nuevos componentes, directivas, etc., y compilar y ejecutar su aplicación en su entorno local.
Creando un Proyecto Angular 6
Bien, suficiente charla. Ensuciémonos las manos y comencemos a programar.
Para comenzar, necesitará Node.js y npm instalados en su máquina.
Ahora, sigamos adelante e instalemos la CLI:
npm install -g @angular/cli
Esto instalará el comando ng
CLI globalmente, debido al interruptor -g
.
Una vez que tengamos eso, podemos obtener el andamio inicial para nuestra aplicación con ng new
:
ng new my-memories --style=scss
Esto creará una carpeta my-memories
, creará todos los archivos necesarios para que su configuración inicial esté lista para comenzar e instalará todos los paquetes necesarios. El --style=scss
es opcional y configurará el compilador para compilar archivos SCSS a CSS, que necesitaremos más adelante.
Una vez que se completa la instalación, puede usar un cd my-memories
y ejecutar ng serve
. Esto iniciará el proceso de compilación y un servidor web local que sirva su aplicación en http://localhost:4200
.
Lo que sucede detrás de escena es que la CLI transpila todos los .ts
(archivos TypeScript) a Vanilla JS, recopila todas las dependencias requeridas de la carpeta de paquetes node_modules
y genera el resultado en un conjunto de archivos que se sirven a través de un servidor web local. que se ejecuta en el puerto 4200.
Archivos de proyecto
Si no está familiarizado con la estructura de carpetas del proyecto de Angular, lo más importante que debe saber es que todo el código relacionado con la aplicación va dentro de la carpeta src
. Por lo general, creará todos sus módulos y directivas en esa carpeta siguiendo la arquitectura de su aplicación (por ejemplo, usuario, carrito, producto).
Configuración inicial
Bien, hasta ahora tenemos la configuración inicial de nuestra aplicación. Vamos a empezar a hacer algunos cambios.
Antes de comenzar, profundicemos un poco en la carpeta src
. La página inicial es index.html
:
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>MyMemories</title> <base href="/"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" type="image/x-icon" href="favicon.ico"> </head> <body> <app-root></app-root> </body> </html>
Aquí vemos algo de HTML básico y la etiqueta <app-root>
. Este es un componente Angular, y donde Angular 6 inserta nuestro código de componente.
Encontraremos el archivo app/app.component.ts
, que tiene el selector app-root
para que coincida con lo que hay en el archivo index.html
.
El componente es una clase de TypeScript decorada y, en este caso, contiene la propiedad de title
. El decorador @Component
le dice a Angular que incluya el comportamiento del componente en la clase. Además del selector, especifica qué archivo HTML representar y qué hojas de estilo usar.
import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent { title = 'app'; }
Si observamos app.component.html
, veremos el enlace de interpolación {{title}}
. Aquí es donde ocurre todo el enlace mágico, y Angular representará el valor de la propiedad del título de la clase y lo actualizará cada vez que cambie.
<!--The content below is only a placeholder and can be replaced.--> <div> <h1> Welcome to {{ title }}! </h1> <img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg=="> </div> <h2>Here are some links to help you start: </h2> <ul> <li> <h2><a target="_blank" rel="noopener" href="https://angular.io/tutorial">Tour of Heroes</a></h2> </li> <li> <h2><a target="_blank" rel="noopener" href="https://github.com/angular/angular-cli/wiki">CLI Documentation</a></h2> </li> <li> <h2><a target="_blank" rel="noopener" href="https://blog.angular.io/">Angular blog</a></h2> </li> </ul>
Avancemos y actualicemos el title
de la clase a 'My Memories!'
.
... export class AppComponent { title = 'My Memories!'; } ...
Veremos que el compilador procesa nuestro cambio y el navegador se actualiza para mostrar nuestro título actualizado.
Esto significa que el ng serve
de Angular 6 observa los cambios de nuestro archivo y los renderiza cada vez que se introduce un cambio en cualquier archivo.
Para hacer que la codificación sea más amigable y evitar la actualización de la página completa cada vez que hacemos cambios, podemos aprovechar el Reemplazo del módulo en caliente (HMR) del paquete web, que solo actualiza la parte de JS/CSS que se cambió en lugar de producir una actualización completa para mostrar sus cambios.
Configuración de HMR
En primer lugar, tenemos que configurar el entorno.
Cree un archivo src/environments/environment.hmr.ts
con el siguiente contenido:
export const environment = { production: false, hmr: true };
Actualice src/environments/environment.prod.ts
y agregue hmr: false
flag al entorno:
export const environment = { production: true, hmr: false };
Luego, actualice src/environments/environment.ts
y agregue hmr: false
flag al entorno allí también:
export const environment = { production: false, hmr: false };
A continuación, en el archivo angular.json
, actualice esta parte:
"projects": { "my-memories": { // ... "architect": { "build": { // ... "configurations": { "hmr":{ "fileReplacements":[ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.hmr.ts" } ] }, // ...
Y en projects
→ my-memories
→ architect
→ serve
→ configurations
:
"projects": { "my-memories": { "architect": { // ... "serve": { // ... "configurations": { "hmr": { "browserTarget": "my-memories:build:hmr" }, // ...
Ahora actualice tsconfig.app.json
para incluir los types
necesarios (bueno, tipo) agregando esto en compilerOptions
:
"compilerOptions": { // ... "types": [ "node" ]
A continuación, instalaremos el @angularclass/hmr
como una dependencia de desarrollo:
npm install --save-dev @angularclass/hmr
Luego configúrelo creando un archivo src/hmr.ts
:
import { NgModuleRef, ApplicationRef } from '@angular/core'; import { createNewHosts } from '@angularclass/hmr'; export const hmrBootstrap = (module: any, bootstrap: () => Promise<NgModuleRef<any>>) => { let ngModule: NgModuleRef<any>; module.hot.accept(); bootstrap().then(mod => ngModule = mod); module.hot.dispose(() => { const appRef: ApplicationRef = ngModule.injector.get(ApplicationRef); const elements = appRef.components.map(c => c.location.nativeElement); const makeVisible = createNewHosts(elements); ngModule.destroy(); makeVisible(); }); };
A continuación, actualice src/main.ts
para usar la función anterior:
import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module'; import { environment } from './environments/environment'; import { hmrBootstrap } from './hmr'; if (environment.production) { enableProdMode(); } const bootstrap = () => platformBrowserDynamic().bootstrapModule(AppModule); if (environment.hmr) { if (module[ 'hot' ]) { hmrBootstrap(module, bootstrap); } else { console.error('HMR is not enabled for webpack-dev-server!'); console.log('Are you using the --hmr flag for ng serve?'); } } else { bootstrap().catch(err => console.log(err)); }
Lo que estamos haciendo aquí es hacer que la llamada de arranque sea una función anónima y luego preguntar si el indicador de environment.hmr
es verdadero. Si es así, llamamos a la función previamente definida desde hmr.ts
que permitió el reemplazo del módulo en caliente; de lo contrario, lo arrancamos como solíamos hacerlo.
Ahora, cuando ng serve --hmr --configuration=hmr
, invocaremos la configuración de hmr
, y cuando hagamos cambios en los archivos, obtendremos actualizaciones sin una actualización completa. El primero --hmr
es para webpack, y --configuration=hmr
es para que Angular use el entorno hmr
.
Aplicación web progresiva (PWA)
Para agregar compatibilidad con Angular 6 PWA y habilitar la carga sin conexión para la aplicación, podemos utilizar uno de los nuevos comandos CLI, ng add
:
ng add @angular/[email protected]
Tenga en cuenta que estoy agregando la versión, ya que la última versión cuando estaba escribiendo este tutorial arrojaba un error. (Puede probar sin él y verificar si funciona para usted usando simplemente ng add @angular/pwa
).
Bien, después de que hayamos ejecutado el comando, veremos muchos cambios en nuestro proyecto. Los cambios más importantes son que agregó:
- Una referencia a
manifest.json
en el archivo de activosangular.json
, para que se incluya en el resultado de la compilación, así como"serviceWorker": true
en las compilaciones de producción - El archivo
ngsw-config.json
con la configuración inicial para almacenar en caché todos los archivos necesarios para que la aplicación se ejecute - Una metaetiqueta
manifest.json
en el archivoindex.html
- El propio archivo
manifest.json
, con una configuración básica para la aplicación - El trabajador del servicio se carga en el módulo de la aplicación
ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production })
(tenga en cuenta que el trabajador del servicio solo estará habilitado en entornos de producción)
Entonces, esto ahora significa que cuando el usuario acceda por primera vez a la URL, los archivos se descargarán. Después de eso, si el usuario intenta acceder a la URL sin servicio de red, la aplicación seguirá funcionando extrayendo esos archivos almacenados en caché.
Agregar la biblioteca de interfaz de usuario de Material Angular 6
Hasta ahora tenemos la configuración inicial y estamos listos para comenzar a construir nuestra aplicación. Para hacer uso de componentes ya construidos, podemos usar la versión Angular 6 de Material.
Para instalar el paquete de material
en nuestra aplicación, volveremos a utilizar ng add
:
ng add @angular/material
Después de ejecutar eso, veremos algunos paquetes nuevos agregados y una configuración de estilo básica:
-
index.html
incluye la fuente Roboto y los íconos de Material -
BrowserAnimationsModule
se agrega a nuestroAppModule
-
angular.json
tiene el tema rosa índigo ya incluido para nosotros
Deberá reiniciar ng serve
para retomar el tema, o puede elegir otro tema preconstruido.
Diseño básico
Para tener el diseño inicial de sidenav, usaremos los esquemas que vienen con Material. Pero está bien si desea utilizar un diseño diferente.
(En pocas palabras, los esquemas le permiten aplicar transformaciones a un proyecto: puede crear, modificar o eliminar archivos según sea necesario. En este caso, crea un diseño de navegación lateral para nuestra aplicación).
ng generate @angular/material:material-nav --name=my-nav
Esto creará un componente sidenav con la configuración mínima lista para comenzar. ¿No es genial?
También ha incluido todos los módulos necesarios en nuestro app.module.ts
.
Dado que usamos SCSS, debemos cambiar el nombre del archivo my- my-nav.component.css
a my-nav.component.scss
y, en my-nav.component.ts
actualizar las styleUrls
de estilo de referencia correspondientes para usar el nuevo nombre.
Ahora, para hacer uso del nuevo componente, vayamos a app.component.html
y eliminemos todo el código inicial, dejando solo:
<app-my-nav></app-my-nav>
Cuando volvamos al navegador, esto es lo que veremos:
Actualicemos los enlaces para tener solo las dos opciones que queremos.
Primero, vamos a crear dos nuevos componentes:
ng gc AddMemory ng generate @angular/material:material-table --name=view-memories
(El segundo es un esquema de material utilizado para crear una tabla).
A continuación, en my-nav
actualizaremos para configurar los enlaces e incluir el <router-outlet>
para mostrar nuestros componentes de contenido:
<mat-sidenav-container class="sidenav-container"> <mat-sidenav #drawer class="sidenav" fixedInViewport="true" [attr.role]="(isHandset$ | async) ? 'dialog' : 'navigation'" [mode]="(isHandset$ | async) ? 'over' : 'side'" [opened]="!(isHandset$ | async)"> <mat-toolbar color="primary">Menu</mat-toolbar> <mat-nav-list> <a mat-list-item [routerLink]="['/add-memory']">Add Memory</a> <a mat-list-item [routerLink]="['/view-memories']">View My Memories</a> </mat-nav-list> </mat-sidenav> <mat-sidenav-content> <mat-toolbar color="primary"> <button type="button" aria-label="Toggle sidenav" mat-icon-button (click)="drawer.toggle()" *ngIf="isHandset$ | async"> <mat-icon aria-label="Side nav toggle icon">menu</mat-icon> </button> <span>my-memories</span> </mat-toolbar> <router-outlet></router-outlet> </mat-sidenav-content> </mat-sidenav-container>
Además, en app.component.html
necesitamos actualizarlo para que solo tenga el <router-outlet>
principal (es decir, eliminar <my-nav>
):

<router-outlet></router-outlet>
A continuación, en el AppModule
incluiremos las rutas:
import { RouterModule, Routes } from '@angular/router'; // ... imports: [ // ... RouterModule.forRoot([ { path: '', component: MyNavComponent, children: [ { path: 'add-memory', component: AddMemoryComponent }, { path: 'view-memories', component: ViewMemoriesComponent } ] }, ]), ]
Tenga en cuenta que estamos configurando MyNavComponent
como principal y los dos componentes que creamos como secundarios. Esto se debe a que incluimos el <router-outlet>
en MyNavComponent
, y cada vez que llegamos a una de esas dos rutas, representaremos el componente secundario donde se colocó el <router-outlet>
.
Luego de esto, cuando sirvamos la app deberíamos ver:
Cree la aplicación (un diario de recuerdos)
Bien, ahora vamos a crear el formulario para guardar nuevos recuerdos en nuestro diario.
Tendremos que importar algunos módulos de material y el módulo de formularios a nuestro app.module.ts
:
import { FormsModule } from '@angular/forms'; import { MatCardModule, MatFormFieldModule, MatInputModule, MatDatepickerModule, MatNativeDateModule } from '@angular/material'; // ... Imports:[ // ... MatCardModule, MatFormFieldModule, MatInputModule, MatDatepickerModule, FormsModule, MatNativeDateModule, // ... ]
Y luego en add-memory.component.html
, agregaremos el formulario:
<form #form="ngForm" (ngSubmit)="onSubmit()"> <mat-card class="memory-card"> <mat-card-title> Add a memory </mat-card-title> <mat-card-content> <mat-form-field> <input disabled matInput placeholder="Select the date..." [(ngModel)]="memory.date" name="date" [matDatepicker]="date"> <mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle> <mat-datepicker disabled="false" #date></mat-datepicker> </mat-form-field> <mat-form-field> <textarea placeholder="Enter your memory..." rows="3" maxlength="300" matInput [(ngModel)]="memory.text" name="memory"></textarea> </mat-form-field> </mat-card-content> <mat-card-actions> <button mat-button type="submit">Save me!</button> </mat-card-actions> </mat-card> </form> <pre> {{ memory | json }} </pre>
Aquí estamos usando una mat-card
y agregando dos campos, una date
y un área de textarea
.
Tenga en cuenta que estamos usando [(ngModel)]
. Esta directiva de Angular unirá la expresión memory.date
y la propiedad de memory
en la clase entre sí, como veremos más adelante. ( [(ngModel)]
es azúcar sintáctico: un atajo para realizar un enlace de datos bidireccional de la clase a la vista y de la vista a la clase. Esto significa que cuando ingresa texto en la vista, memory.date
reflejará esos cambios en la instancia de clase, y si realiza cambios en memory.date
en la instancia de clase, la vista reflejará los cambios).
En add-memory.component.ts
, el código se verá así:
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-add-memory', templateUrl: './add-memory.component.html', styleUrls: ['./add-memory.component.scss'] }) export class AddMemoryComponent implements OnInit { memory: any = {}; constructor() { } ngOnInit() { } onSubmit() { console.log(this.memory); } }
Aquí, estamos inicializando la propiedad de memory
vinculada a través ngModel
. Cuando se crea una instancia del componente AddMemoryComponent
, memory
será un objeto vacío. Luego, cuando se ejecute la directiva ngModel
, podrá asignar el valor de entrada a memory.date
y memory.text
. Si no hiciéramos esto, obtendríamos un error de Cannot set property 'date/text' of undefined
.
Mientras tanto, add-memory.component.scss
debe tener:
.memory-card { min-width: 150px; max-width: 400px; width: 100%; margin: auto; } .mat-form-field { width: 100%; }
Ya que tenemos <pre> {{ memory | json }} </pre>
<pre> {{ memory | json }} </pre>
podemos ver el estado actual de la memory
en la vista. Si vamos al navegador, aquí está el resultado hasta ahora:
En la vista, vinculamos el formulario mediante (ngSubmit)="onSubmit()"
a la función onSubmit
en la clase.
onSubmit() { console.log(this.memory); }
Entonces, cuando haces clic en "¡Sálvame!" botón, obtendrá la representación interna de la entrada del usuario enviada al registro de la consola:
Tutorial de Angular 6: Conexión con Firebase
Lo que haremos a continuación es conectar nuestro proyecto a Firebase para guardar nuestros recuerdos.
Primero, iremos a la consola Firebase y crearemos un proyecto allí.
En segundo lugar, instalaremos los paquetes firebase
y angularfire2
:
npm install firebase angularfire2 --save
Y luego en cada uno de estos tres archivos:
-
/src/environments/environment.ts
-
/src/environments/environment.hmr.ts
-
/src/environments/environment.prod.ts
… agregaremos nuestra configuración de Firebase:
export const environment = { // ... firebase: { apiKey: '<your-key>', authDomain: '<your-project-authdomain>', databaseURL: '<your-database-URL>', projectId: '<your-project-id>', storageBucket: '<your-storage-bucket>', messagingSenderId: '<your-messaging-sender-id>' } };
Puede obtener los detalles de configuración necesarios para los archivos anteriores haciendo clic en "Agregar Firebase a su aplicación web" en la página de descripción general del proyecto.
Después de eso, incluiremos los módulos de Firebase en nuestro app.module.ts
:
import { AngularFireModule } from 'angularfire2'; import { AngularFireDatabaseModule } from 'angularfire2/database'; import { environment } from '../environments/environment'; // ... Imports:[ // ... AngularFireModule.initializeApp(environment.firebase), AngularFireDatabaseModule, // ... ]
Y en add-memory.component.ts
, inyectamos la base de datos en el constructor y guardamos los valores del formulario en la base de datos. Cuando la promesa de inserción de Firebase es exitosa, registramos el éxito en la consola y reiniciamos el modelo:
import { AngularFireDatabase } from 'angularfire2/database'; // ... constructor(private db: AngularFireDatabase) { } // ... onSubmit() { this.memory.date = new Date(this.memory.date).valueOf(); this.db.list('memories').push(this.memory) .then(_ => { this.memory = {} console.log('success') }) }
Deberá permitir el acceso público a las reglas de la base de datos, para que los usuarios anónimos puedan leer y escribir en ella. Tenga en cuenta que con esta configuración, cualquier usuario podrá leer/cambiar/eliminar los datos de su aplicación. Asegúrese de configurar sus reglas en consecuencia antes de pasar a producción.
Además, para recoger los cambios en el entorno, deberá reiniciar el proceso de ng serve
.
Ahora, cuando volvamos al navegador y hagamos clic en el botón Guardar, veremos que la memoria se agregó a la base de datos:
Echemos un vistazo a cómo podemos recuperar nuestros recuerdos y mostrarlos en la tabla Material.
Cuando creamos la tabla usando ng generate @angular/material:material-table --name=view-memories', we automatically got a file
view-memories/view-memories-datasource.ts`. Este archivo contiene datos falsos, por lo que tendremos que cambiarlo para comenzar a extraerlo de Firebase.
En view-memories-datasource.ts
, eliminaremos EXAMPLE_DATA
y estableceremos una matriz vacía:
export class ViewMemoriesDataSource extends DataSource<ViewMemoriesItem> { data: ViewMemoriesItem[] = []; // ...
Y en getSortedData
actualizaremos los nombres de los campos:
private getSortedData(data: ViewMemoriesItem[]) { if (!this.sort.active || this.sort.direction === '') { return data; } return data.sort((a, b) => { const isAsc = this.sort.direction === 'asc'; switch (this.sort.active) { case 'text': return compare(a.name, b.name, isAsc); case 'date': return compare(+a.id, +b.id, isAsc); default: return 0; } }); }
En view-memories.component.html
actualizaremos los nombres de las columnas a la date
y el text
de nuestro modelo de memoria. Tenga en cuenta que, dado que guardamos la fecha en formato de milisegundos, aquí estamos usando una tubería de fecha para transformar el valor para mostrar en un formato de fecha más amigable para los humanos. Por último, estamos eliminando [length]="dataSource.data.length"
del paginador, ya que cargaremos los datos de forma asíncrona desde Firebase:
<div class="mat-elevation-z8"> <table mat-table #table [dataSource]="dataSource" matSort aria-label="Elements"> <!-- Id Column --> <ng-container matColumnDef="date"> <th mat-header-cell *matHeaderCellDef mat-sort-header>Date</th> <td mat-cell *matCellDef="let row">{{row.date | date:'short'}}</td> </ng-container> <!-- Name Column --> <ng-container matColumnDef="text"> <th mat-header-cell *matHeaderCellDef mat-sort-header>Text</th> <td mat-cell *matCellDef="let row">{{row.text}}</td> </ng-container> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> </table> <mat-paginator #paginator [pageIndex]="0" [pageSize]="50" [pageSizeOptions]="[25, 50, 100, 250]"> </mat-paginator> </div>
Cambie view-memories.component.css
a view-memories.component.scss
y configure el estilo de la tabla:
table{ width: 100%; }
En view-memories.component.ts
, cambiaremos styleUrls
para reflejar el cambio de nombre anterior a ./view-memories.component.scss
. También actualizaremos la matriz de columnas displayedColumns
para que sea ['date', 'text']
y configuraremos la fuente de datos de la tabla para obtener datos de Firebase.
Lo que sucede aquí es que nos suscribimos a la lista de memorias y, cuando recibimos los datos, creamos una instancia de ViewMemoriesDataSource
y configuramos su propiedad de datos con los datos de Firebase.
this.subscription = this.db.list<ViewMemoriesItem>('memories').valueChanges().subscribe(d=>{ console.log('data streaming'); this.dataSource = new ViewMemoriesDataSource(this.paginator, this.sort); this.dataSource.data = d; });
Firebase devuelve una matriz Observable de estilo ReactiveX.
Tenga en cuenta que estamos this.db.list<ViewMemoriesItem>('memories')
, los valores extraídos de la ruta de 'memories'
, a ViewMemoriesItem
. De esto se ocupa la biblioteca angularfire2
.
También incluimos la llamada de cancelación de unsubscribe
dentro del gancho onDestroy
del ciclo de vida del componente Angular.
import { Component, OnInit, ViewChild, OnDestroy } from '@angular/core'; import { MatPaginator, MatSort } from '@angular/material'; import { ViewMemoriesDataSource, ViewMemoriesItem } from './view-memories-datasource'; import { AngularFireDatabase } from 'angularfire2/database'; import { Subscription } from 'rxjs'; import { map, first } from 'rxjs/operators'; @Component({ selector: 'app-view-memories', templateUrl: './view-memories.component.html', styleUrls: ['./view-memories.component.scss'] }) export class ViewMemoriesComponent implements OnInit, OnDestroy{ @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; dataSource: ViewMemoriesDataSource; /** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */ displayedColumns = ['date', 'text']; subscription: Subscription; constructor(private db: AngularFireDatabase) { } ngOnInit() { this.subscription = this.db.list<ViewMemoriesItem>('memories').valueChanges().subscribe(d=>{ console.log('data streaming'); this.dataSource = new ViewMemoriesDataSource(this.paginator, this.sort); this.dataSource.data = d; }); } ngOnDestroy(): void { this.subscription.unsubscribe(); } }
Implementación en Firebase Hosting
Ahora, para que nuestra aplicación esté activa, implementémosla en Firebase Hosting. Para eso, instalaremos Firebase CLI, que hace que el comando firebase
esté disponible:
npm install -g firebase-tools
Ahora podemos usar Firebase CLI para iniciar sesión:
firebase login
Esto le pedirá que seleccione su cuenta de Google.
A continuación, inicializaremos el proyecto y configuraremos Firebase Hosting:
firebase init
Simplemente seleccionaremos la opción Hosting.
A continuación, cuando se nos solicite la ruta, la configuraremos en dist/my-memories
. Cuando se nos pregunte si configurarlo como una aplicación de una sola página (es decir, reescribir todas las URL en /index.html
), responderemos "sí".
Finalmente, presionaremos, “El archivo dist/my-memories/index.html ya existe. ¿Sobrescribir?" Aquí diremos “no”.
Esto creará los archivos de configuración de Firebase .firebaserc
y firebase.json
con la configuración proporcionada.
El último paso es ejecutar:
ng build --prod firebase deploy
Y con eso, habremos publicado la aplicación en Firebase, que proporciona una URL para que naveguemos, como https://my-memories-b4c52.firebaseapp.com/view-memories, donde puede ver mi propia publicación. manifestación.
¡Vaya, has pasado por el tutorial! Espero que lo hayan disfrutado. También puede consultar el código completo en GitHub.
Un paso a la vez
Angular es un marco muy poderoso para crear aplicaciones web. Ha existido durante mucho tiempo y ha demostrado su valía tanto para aplicaciones pequeñas y simples como para aplicaciones grandes y complejas: Angular 6 no es una excepción aquí.
En el futuro, Angular planea seguir mejorando y siguiendo nuevos paradigmas web, como los componentes web (Angular Elements). Si está interesado en crear aplicaciones híbridas, puede consultar Ionic, que utiliza Angular como marco subyacente.
Este tutorial cubrió pasos muy básicos para comenzar a usar Angular, Material y Firebase. Pero debe tener en cuenta que para las aplicaciones del mundo real, deberá agregar la validación y, para que su aplicación sea más fácil de mantener y escalar, probablemente desee seguir las mejores prácticas, como el uso de servicios, componentes reutilizables, etc. Ese tendrá que ser el tema de otro artículo, ¡con suerte, este fue suficiente para despertar su apetito por el desarrollo angular!