Tutorial Angular 6: nuove funzionalità con nuova potenza

Pubblicato: 2022-03-11

Angular 6 è uscito! Le modifiche più importanti riguardano la CLI e il modo in cui i servizi vengono iniettati. Se stai cercando di scrivere la tua prima app Angular 6, o app Angular/Firebase, in questo tutorial, esamineremo i passaggi di base della configurazione iniziale e creeremo una piccola app diario.

Angular 6: Le basi

Se non hai mai usato Angular prima, lascia che te ne dia una breve descrizione e come funziona.

Angular è un framework JavaScript progettato per supportare la creazione di applicazioni a pagina singola (SPA) sia per desktop che per dispositivi mobili.

Il framework include una suite completa di direttive e moduli che consentono di implementare facilmente alcuni degli scenari più comuni per un'app Web, come navigazione, autorizzazione, moduli e report. Inoltre viene fornito con tutti i pacchetti necessari per aggiungere test utilizzando il framework Jasmine ed eseguirli utilizzando i test runner Karma o Protractor.

L'architettura angolare si basa su componenti, modelli, direttive e servizi. Fornisce un meccanismo di inserimento delle dipendenze integrato per i tuoi servizi, nonché un'associazione dati bidirezionale per connettere le tue viste con il codice del tuo componente.

Angular usa TypeScript, un superset tipizzato di JS, e renderà alcune cose più facili, specialmente se provieni da un background linguistico tipizzato.

Angular 6: Nuove funzionalità

Un breve riepilogo delle nuove funzionalità di Angular 6:

  • Una politica di sincronizzazione dei numeri di versione principali per i pacchetti del framework ( @angular/core , @angular/common , @angular/compiler e così via), CLI, Material e CDK. Ciò contribuirà a rendere più chiara la compatibilità incrociata in futuro: puoi dire da una rapida occhiata al numero di versione se i pacchetti di chiavi sono compatibili tra loro.
  • Nuovi comandi CLI ng :
    • ng update per aggiornare le versioni dei pacchetti in modo intelligente, aggiornando le versioni delle dipendenze e mantenendole sincronizzate. (Ad esempio, quando si esegue ng update @angular/core , tutti i framework verranno aggiornati così come RxJS.) Eseguirà anche gli schemi se il pacchetto li include. (Se una versione più recente include modifiche sostanziali che richiedono modifiche al codice, lo schema aggiornerà il codice per te.)
    • ng add per aggiungere nuovi pacchetti (ed eseguire script, se applicabile)
  • I servizi ora fanno riferimento ai moduli che li forniranno, invece dei moduli che fanno riferimento ai servizi, come li avevano prima.

Come esempio del significato di quest'ultima modifica, l'aspetto del tuo codice:

 @NgModule({ // ... providers: [MyService] })

...con questa particolare modifica in Angular 6, sembrerà:

 @Injectabe({ providedIn: 'root', })

Questi sono chiamati provider scomponibili ad albero e consentono al compilatore di rimuovere i servizi non referenziati risultando in bundle di dimensioni inferiori.

Angolo 6 CLI

L'interfaccia della riga di comando ng è un elemento molto importante di Angular e ti consente di muoverti più velocemente durante la codifica della tua app.

Con l'interfaccia a riga di comando puoi eseguire facilmente lo scaffold della configurazione iniziale dell'app, generare nuovi componenti, direttive e così via e creare ed eseguire l'app nel tuo ambiente locale.

Creazione di un progetto Angular 6

Ok, basta parlare. Sporciamoci le mani e iniziamo a programmare.

Per iniziare, avrai bisogno di Node.js e npm installati sul tuo computer.

Ora andiamo avanti e installiamo la CLI:

 npm install -g @angular/cli

Questo installerà il comando ng CLI a livello globale, a causa -g .

Una volta che lo abbiamo, possiamo ottenere lo scaffold iniziale per la nostra app con ng new :

 ng new my-memories --style=scss

Questo creerà una cartella my-memories , creerà tutti i file necessari per preparare l'installazione iniziale e installerà tutti i pacchetti necessari. L' --style=scss è opzionale e imposterà il compilatore per compilare i file SCSS in CSS, di cui avremo bisogno in seguito.

Una volta completata l'installazione, puoi cd my-memories ed eseguire ng serve . Questo avvierà il processo di compilazione e un server Web locale che serve la tua app all'indirizzo http://localhost:4200 .

Un'app Angular 6 subito dopo l'impalcatura

Quello che sta succedendo dietro le quinte è che la CLI traspilisce tutti i .ts (file TypeScript) in vanilla JS, raccoglie tutte le dipendenze richieste dalla cartella dei pacchetti node_modules e restituisce il risultato in una serie di file che vengono serviti tramite un server Web locale che gira sulla porta 4200.

File di progetto

Se non hai familiarità con la struttura delle cartelle del progetto di Angular, la cosa più importante che devi sapere è che tutto il codice relativo all'app va all'interno della cartella src . Di solito creerai tutti i moduli e le direttive in quella cartella seguendo l'architettura dell'app (ad esempio utente, carrello, prodotto).

La struttura delle cartelle del progetto Angular 6

Configurazione iniziale

Ok, finora abbiamo la configurazione iniziale per la nostra app. Iniziamo ad apportare alcune modifiche.

Prima di iniziare, scaviamo un po' nella cartella src . La pagina iniziale è 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>

Qui vediamo alcuni codici HTML di base e il <app-root> . Questo è un componente Angular e dove Angular 6 inserisce il nostro codice componente.

Troveremo il file app/app.component.ts , che ha il selettore app-root in modo che corrisponda a ciò che è nel file index.html .

Il componente è una classe TypeScript decorata e, in questo caso, contiene la proprietà title . Il decoratore @Component dice ad Angular di includere il comportamento del componente nella classe. Oltre al selettore, specifica quale file HTML di cui eseguire il rendering e quali fogli di stile utilizzare.

 import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent { title = 'app'; }

Se osserviamo app.component.html , vedremo l'associazione di interpolazione {{title}} . È qui che avviene tutto il binding magico e Angular renderà il valore della proprietà del titolo della classe e lo aggiornerà ogni volta che cambia.

 <!--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>

Andiamo avanti e aggiorniamo il title della classe in 'My Memories!' .

 ... export class AppComponent { title = 'My Memories!'; } ...

Vedremo il compilatore elaborare la nostra modifica e l'aggiornamento del browser per mostrare il nostro titolo aggiornato.

Ciò significa che ng serve di Angular 6 controlla le modifiche ai nostri file ed esegue il rendering ogni volta che viene introdotta una modifica in qualsiasi file.

Per rendere la codifica più semplice ed evitare l'aggiornamento dell'intera pagina ogni volta che apportiamo modifiche, possiamo sfruttare il webpack Hot Module Replacement (HMR), che aggiorna semplicemente il blocco di JS/CSS che è stato modificato invece di produrre un aggiornamento completo per mostra le tue modifiche.

Configurazione dell'HMR

In primo luogo, dobbiamo creare l'ambiente.

Crea un file src/environments/environment.hmr.ts con i seguenti contenuti:

 export const environment = { production: false, hmr: true };

Aggiorna src/environments/environment.prod.ts e aggiungi hmr: false flag all'ambiente:

 export const environment = { production: true, hmr: false };

Quindi aggiorna src/environments/environment.ts e aggiungi hmr: false flag all'ambiente:

 export const environment = { production: false, hmr: false };

Successivamente nel file angular.json , aggiorna questa parte:

 "projects": { "my-memories": { // ... "architect": { "build": { // ... "configurations": { "hmr":{ "fileReplacements":[ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.hmr.ts" } ] }, // ...

E sotto i projectsmy-memories → l' architect → il serveconfigurations :

 "projects": { "my-memories": { "architect": { // ... "serve": { // ... "configurations": { "hmr": { "browserTarget": "my-memories:build:hmr" }, // ...

Ora aggiorna tsconfig.app.json per includere i types necessari (beh, tipo) aggiungendo questo in compilerOptions :

 "compilerOptions": { // ... "types": [ "node" ]

Successivamente, installeremo il modulo @angularclass/hmr come dipendenza di sviluppo:

 npm install --save-dev @angularclass/hmr

Quindi configuralo creando un file 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(); }); };

Quindi, aggiorna src/main.ts per utilizzare la funzione precedente:

 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)); }

Quello che stiamo facendo qui è rendere bootstrap una funzione anonima e poi chiedere se il flag environment.hmr è vero. Se lo è, chiamiamo la funzione precedentemente definita da hmr.ts che ha consentito la sostituzione del modulo caldo; in caso contrario, lo eseguiamo come una volta.

Ora, quando eseguiamo ng serve --hmr --configuration=hmr , invocheremo la configurazione hmr e quando apportiamo modifiche ai file, otterremo aggiornamenti senza un aggiornamento completo. Il primo --hmr è per webpack e --configuration=hmr è per Angular per utilizzare l'ambiente hmr .

App Web progressiva (PWA)

Per aggiungere il supporto per Angular 6 PWA e abilitare il caricamento offline per l'app, possiamo utilizzare uno dei nuovi comandi CLI, ng add :

 ng add @angular/[email protected]

Nota che sto aggiungendo la versione, poiché l'ultima versione quando stavo scrivendo questo tutorial generava un errore. (Puoi provare senza di esso e verificare se funziona per te usando semplicemente ng add @angular/pwa .)

Ok, quindi dopo aver eseguito il comando vedremo molte modifiche al nostro progetto. Le modifiche più importanti sono che ha aggiunto:

  • Un riferimento a manifest.json nel file di asset angular.json , in modo che sia incluso nell'output della build, così come "serviceWorker": true nelle build di produzione
  • Il file ngsw-config.json con la configurazione iniziale per memorizzare nella cache tutti i file necessari per l'esecuzione dell'app
  • Un meta tag manifest.json nel file index.html
  • Il file manifest.json stesso, con una configurazione di base per l'app
  • Il carico di lavoro del servizio nel modulo dell'app ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production }) (si noti che il lavoratore del servizio sarà abilitato solo negli ambienti di produzione)

Quindi, questo ora significa che quando l'utente accede per la prima volta all'URL, i file verranno scaricati. Successivamente, se l'utente tenta di accedere all'URL senza il servizio di rete, l'app continuerà a funzionare estraendo i file memorizzati nella cache.

Aggiunta della libreria dell'interfaccia utente di Material Angular 6

Finora abbiamo la configurazione iniziale e siamo pronti per iniziare a creare la nostra app. Per utilizzare componenti già costruiti, possiamo utilizzare la versione Angular 6 di Material.

Per installare il pacchetto material sulla nostra app, utilizzeremo nuovamente ng add :

 ng add @angular/material

Dopo averlo eseguito, vedremo alcuni nuovi pacchetti aggiunti e alcune configurazioni di stile di base:

  • index.html include il carattere Roboto e le icone Materiale
  • BrowserAnimationsModule viene aggiunto al nostro AppModule
  • angular.json ha già incluso il tema rosa indaco per noi

Indica la tua scelta di un tema Angular 6 predefinito

Dovrai riavviare ng serve per riprendere il tema, oppure puoi scegliere un altro tema predefinito.

Correlati: crea app Web ultramoderne con materiale angolare

Disposizione di base

Per avere il layout iniziale del sidenav, utilizzeremo gli schemi forniti con Material. Ma va bene se vuoi usare un layout diverso.

(In poche parole, gli schemi ti consentono di applicare trasformazioni a un progetto: puoi creare, modificare o eliminare i file secondo necessità. In questo caso, crea un'impalcatura di un layout sidenav per la nostra app.)

 ng generate @angular/material:material-nav --name=my-nav

Questo creerà un componente sidenav con la configurazione minima pronta per iniziare. Non è fantastico?

Ha anche incluso tutti i moduli necessari nel nostro app.module.ts .

Un componente Angular 6 "my-nav" di nuova creazione

Poiché stiamo usando SCSS, dobbiamo rinominare il file my- my-nav.component.css in my-nav.component.scss e in my-nav.component.ts aggiornare i corrispondenti styleUrls di riferimento per utilizzare il nuovo nome.

Ora per utilizzare il nuovo componente, andiamo su app.component.html e rimuoviamo tutto il codice iniziale, lasciando solo:

 <app-my-nav></app-my-nav>

Quando torniamo al browser, ecco cosa vedremo:

Un layout a quattro riquadri con Menu nell'angolo in alto a sinistra, i miei ricordi accanto e tre collegamenti numerati sotto Menu; il quarto riquadro è vuoto

Aggiorniamo i collegamenti per avere solo le due opzioni che vogliamo.

Per prima cosa, creiamo due nuovi componenti:

 ng gc AddMemory ng generate @angular/material:material-table --name=view-memories

(Il secondo è uno schema materiale utilizzato per creare una tabella.)

Successivamente, su my-nav ci aggiorneremo per impostare i collegamenti e includere il <router-outlet> per visualizzare i nostri componenti di contenuto:

 <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>

Inoltre, in app.component.html dobbiamo aggiornarlo per avere solo il principale <router-outlet> (ad esempio, rimuovere <my-nav> ):

 <router-outlet></router-outlet>

Successivamente, su AppModule includeremo i percorsi:

 import { RouterModule, Routes } from '@angular/router'; // ... imports: [ // ... RouterModule.forRoot([ { path: '', component: MyNavComponent, children: [ { path: 'add-memory', component: AddMemoryComponent }, { path: 'view-memories', component: ViewMemoriesComponent } ] }, ]), ]

Si noti che stiamo impostando MyNavComponent come genitore e i due componenti che abbiamo creato come figli. Questo perché abbiamo incluso <router-outlet> in MyNavComponent e ogni volta che raggiungiamo uno di questi due percorsi, renderemo il componente figlio in cui è stato posizionato <router-outlet> .

Dopodiché, quando serviamo l'app dovremmo vedere:

I collegamenti a sinistra sono stati sostituiti con Aggiungi memoria e Visualizza i miei ricordi, con quest'ultimo selezionato. Il riquadro vuoto ora ha una tabella con numeri ID e nomi.

Crea l'app (Un diario dei ricordi)

Ok, ora creiamo il modulo per salvare nuovi ricordi nel nostro diario.

Avremo bisogno di importare alcuni moduli materiali e il modulo moduli nel nostro app.module.ts :

 import { FormsModule } from '@angular/forms'; import { MatCardModule, MatFormFieldModule, MatInputModule, MatDatepickerModule, MatNativeDateModule } from '@angular/material'; // ... Imports:[ // ... MatCardModule, MatFormFieldModule, MatInputModule, MatDatepickerModule, FormsModule, MatNativeDateModule, // ... ]

E poi in add-memory.component.html , aggiungeremo il modulo:

 <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>

Qui stiamo usando una mat-card e aggiungendo due campi, una date e un'area di textarea .

Si noti che stiamo usando [(ngModel)] . Questa direttiva Angular legherà tra loro l'espressione memory.date e la proprietà memory nella classe, come vedremo in seguito. ( [(ngModel)] è zucchero sintattico, una scorciatoia per eseguire l'associazione dati bidirezionale dalla classe alla vista e dalla vista alla classe. Ciò significa che quando inserisci del testo nella vista, memory.date rifletterà tali modifiche nell'istanza della classe e se apporti modifiche a memory.date nell'istanza della classe, la vista rifletterà le modifiche.)

In add-memory.component.ts , il codice sarà simile a questo:

 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); } }

Qui stiamo inizializzando la proprietà di memory legata tramite ngModel . Quando viene creata un'istanza del componente AddMemoryComponent , memory sarà un oggetto vuoto. Quindi, quando viene eseguita la direttiva ngModel , sarà in grado di assegnare il valore di input a memory.date e memory.text . Se non lo facessimo, otterremmo un errore di Cannot set property 'date/text' of undefined .

Nel frattempo, add-memory.component.scss deve avere:

 .memory-card { min-width: 150px; max-width: 400px; width: 100%; margin: auto; } .mat-form-field { width: 100%; }

Poiché abbiamo <pre> {{ memory | json }} </pre> <pre> {{ memory | json }} </pre> possiamo vedere lo stato corrente della memory nella vista. Se andiamo al browser, ecco il risultato finora:

Il prototipo dell'app diario "my-memories", che mostra la rappresentazione interna dell'input dell'utente (data e testo).

Nella vista, abbiamo associato il modulo tramite (ngSubmit)="onSubmit()" alla funzione onSubmit nella classe.

 onSubmit() { console.log(this.memory); }

Quindi, quando fai clic su "Salvami!" pulsante, otterrai la rappresentazione interna dell'input dell'utente inviato al registro della console:

La rappresentazione interna dell'input dell'utente nel registro della console.

Tutorial Angular 6: Connessione con Firebase

Quello che faremo dopo è collegare il nostro progetto a Firebase per salvare i nostri ricordi.

Per prima cosa, andremo alla console Firebase e creeremo un progetto lì.

Aggiunta di un progetto Firebase.

In secondo luogo, installeremo i pacchetti firebase e angularfire2 :

 npm install firebase angularfire2 --save

E poi in ciascuno di questi tre file:

  1. /src/environments/environment.ts
  2. /src/environments/environment.hmr.ts
  3. /src/environments/environment.prod.ts

…aggiungeremo la nostra configurazione 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>' } };

Puoi ottenere i dettagli di configurazione richiesti per i file di cui sopra facendo clic su "Aggiungi Firebase alla tua app Web" nella pagina di panoramica del progetto.

Successivamente, includeremo i moduli Firebase nel nostro app.module.ts :

 import { AngularFireModule } from 'angularfire2'; import { AngularFireDatabaseModule } from 'angularfire2/database'; import { environment } from '../environments/environment'; // ... Imports:[ // ... AngularFireModule.initializeApp(environment.firebase), AngularFireDatabaseModule, // ... ]

E in add-memory.component.ts , inseriamo il database nel costruttore e salviamo i valori dal modulo al database. Quando la promessa push di Firebase ha esito positivo, registriamo il successo nella console e reimpostare il modello:

 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') }) } 

Consentire l'accesso in lettura e scrittura al database di Firebase.

Dovrai consentire l'accesso pubblico alle regole del database, in modo che gli utenti anonimi possano leggere e scrivere su di esso. Tieni presente che con questa configurazione, qualsiasi utente sarà in grado di leggere/modificare/eliminare i dati dell'app. Assicurati di impostare le tue regole di conseguenza prima di passare alla produzione.

Inoltre, per raccogliere le modifiche all'ambiente sarà necessario riavviare il processo ng serve .

Ora, quando torniamo al browser e facciamo clic sul nostro pulsante di salvataggio, vedremo che la memoria è stata aggiunta al database:

La nostra memoria di prova è stata aggiunta al database Firebase della nostra app diario.

Diamo un'occhiata a come possiamo recuperare i nostri ricordi e visualizzarli nella tabella Materiale.

Quando abbiamo creato la tabella usando ng generate @angular/material:material-table --name=view-memories', we automatically got a file view-memories/view-memories-datasource.ts`. Questo file contiene dati falsi, quindi dovremo cambiarlo per iniziare a estrarre da Firebase.

In view-memories-datasource.ts , rimuoveremo EXAMPLE_DATA e imposteremo un array vuoto:

 export class ViewMemoriesDataSource extends DataSource<ViewMemoriesItem> { data: ViewMemoriesItem[] = []; // ...

E in getSortedData aggiorneremo i nomi dei campi:

 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; } }); }

In view-memories.component.html aggiorneremo i nomi delle colonne alla date e il text dal nostro modello di memoria. Si noti che poiché abbiamo salvato la data in formato millisecondi, qui stiamo usando una pipe della data per trasformare il valore per la visualizzazione in un formato di data più adatto all'uomo. Infine, stiamo rimuovendo [length]="dataSource.data.length" dall'impaginatore, poiché caricheremo i dati in modo asincrono da 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>

Cambia view-memories.component.css in view-memories.component.scss e imposta lo stile della tabella:

 table{ width: 100%; }

In view-memories.component.ts , cambieremo gli styleUrls per riflettere la ridenominazione sopra in ./view-memories.component.scss . Aggiorneremo anche l'array displayedColumns in modo che sia ['date', 'text'] e configureremo l'origine dati della tabella per ottenere i dati da Firebase.

Quello che sta succedendo qui è che ci stiamo iscrivendo all'elenco delle memorie e quando riceviamo i dati, istanziamo ViewMemoriesDataSource e impostiamo la sua proprietà data con i dati da 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 restituisce un array osservabile in stile ReactiveX.

Nota che stiamo this.db.list<ViewMemoriesItem>('memories') —i valori estratti dal percorso 'memories' —a ViewMemoriesItem . Questo è curato dalla libreria angularfire2 .

Abbiamo anche incluso la chiamata di unsubscribe dell'iscrizione all'interno onDestroy del ciclo di vita 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(); } }
Correlati: Creazione di applicazioni mobili multipiattaforma in tempo reale: esempi utilizzando Ionic Framework e Firebase

Distribuzione su Firebase Hosting

Ora, per rendere attiva la nostra app, distribuiamola su Firebase Hosting. Per questo, installeremo la CLI Firebase, che rende disponibile il comando firebase :

 npm install -g firebase-tools

Ora possiamo usare Firebase CLI per accedere:

 firebase login

Questo ti chiederà di selezionare il tuo account Google.

Successivamente, inizializzeremo il progetto e configureremo Firebase Hosting:

 firebase init

Selezioneremo semplicemente l'opzione Hosting.

Successivamente, quando ci viene chiesto il percorso, lo imposteremo su dist/my-memories . Quando ci viene chiesto se configurarla come app a pagina singola (ovvero riscrivere tutti gli URL in /index.html ), risponderemo "sì".

Infine, premeremo "File dist/my-memories/index.html esiste già. Sovrascrivi?" Qui diremo "no".

Questo creerà i file di configurazione di Firebase .firebaserc e firebase.json con la configurazione fornita.

L'ultimo passaggio è eseguire:

 ng build --prod firebase deploy

E con ciò, avremo pubblicato l'app su Firebase, che fornisce un URL su cui navigare, come https://my-memories-b4c52.firebaseapp.com/view-memories, dove puoi visualizzare i miei demo.


Wow, hai seguito il tutorial! Spero ti sia piaciuto. Puoi anche controllare il codice completo su GitHub.

Un passo alla volta

Angular è un framework molto potente per la creazione di app Web. È disponibile da molto tempo e si è dimostrato valido per app piccole e semplici e per app grandi e complesse allo stesso modo: Angular 6 non fa eccezione qui.

Andando avanti, Angular prevede di continuare a migliorare e seguire i nuovi paradigmi web come i componenti web (Angular Elements). Se sei interessato a creare app ibride, puoi dare un'occhiata a Ionic, che utilizza Angular come framework sottostante.

Questo tutorial ha coperto i passaggi di base per iniziare a utilizzare Angular, Material e Firebase. Ma dovresti tenere conto del fatto che per le applicazioni del mondo reale, dovrai aggiungere la convalida e per semplificare la manutenzione e la scalabilità della tua applicazione, probabilmente vorrai seguire le migliori pratiche come l'utilizzo di servizi, componenti riutilizzabili, ecc. Questo dovrà essere l'argomento di un altro articolo: si spera che questo sia stato sufficiente per stuzzicare il tuo appetito per lo sviluppo angolare!

Correlati: Tutti i vantaggi, nessun problema: un tutorial di Angular 9