Tutorial Angular 6: Nuove caratteristiche con nuova potenza

Angular 6 è uscito! I cambiamenti più rilevanti sono nella sua CLI e nel modo in cui i servizi vengono iniettati. Se stai cercando di scrivere la tua prima app Angular 6 – o un’app Angular/Firebase – in questo tutorial, andremo oltre i passi base della configurazione iniziale e creeremo una piccola app diario.

Angular 6: Le basi

Se non hai mai usato Angular prima, lascia che ti dia una breve descrizione di esso e di come funziona.

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

Il framework include una suite completa di direttive e moduli che ti permettono di implementare facilmente alcuni degli scenari più comuni per una web app, come la navigazione, l’autorizzazione, i moduli e il reporting. Viene anche fornito con tutti i pacchetti necessari per aggiungere test utilizzando il framework Jasmine ed eseguirli utilizzando i test runner Karma o Protractor.

L’architettura Angular è basata su componenti, modelli, direttive e servizi. Fornisce un meccanismo di dependency injection integrato per i vostri servizi, così come un data binding bidirezionale per collegare le vostre viste con il vostro codice componente.

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

Angular 6: Nuove caratteristiche

Un breve riassunto delle nuove caratteristiche in Angular 6:

  • Una politica di sincronizzazione dei numeri di versione principali per i pacchetti del framework (@angular/core, @angular/common, @angular/compiler, ecc.), CLI, Material e CDK. Questo aiuterà a rendere la compatibilità incrociata più chiara in futuro: Si può dire da una rapida occhiata al numero di versione se i pacchetti chiave sono compatibili tra loro.
  • Nuovi ng comandi CLI:
    • 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 saranno aggiornati così come RxJS.) Eseguirà anche gli schemi se il pacchetto li include. (Se una versione più recente include modifiche di rottura che richiedono cambiamenti nel codice, lo schema aggiornerà il codice per voi.)
    • ng add per aggiungere nuovi pacchetti (ed eseguire gli script, se applicabile)
  • I servizi ora fanno riferimento ai moduli che li forniranno, invece di moduli che fanno riferimento ai servizi, come era solito fare.

Come esempio di cosa significhi quest’ultimo cambiamento, dove il tuo codice prima assomigliava a:

@NgModule({ // ... providers: })

…con questo particolare cambiamento in Angular 6, assomiglierà a:

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

Questi sono chiamati provider tree-shakeable e permettono al compilatore di rimuovere i servizi non referenziati con conseguente bundle di dimensioni più piccole.

Angular 6 CLI

L’interfaccia nga riga di comando è un pezzo molto importante di Angular e ti permette di muoverti più velocemente quando codifichi la tua app.

Con la CLI puoi impacchettare la configurazione iniziale della tua app molto facilmente, generare nuovi componenti, direttive, ecc, e costruire ed eseguire la tua app nel tuo ambiente locale.

Creare un progetto Angular 6

Ok, basta parlare. Sporchiamoci le mani e iniziamo a codificare.

Per iniziare, avrai bisogno di Node.js e npm installati sulla tua macchina.

Ora, andiamo avanti e installiamo la CLI:

npm install -g @angular/cli

Questo installerà il comando ng CLI globalmente, grazie allo switch -g.

Una volta che abbiamo questo, possiamo ottenere l’impalcatura iniziale per la nostra applicazione con ng new:

ng new my-memories --style=scss

Questo creerà una cartella my-memories, creerà tutti i file necessari per ottenere la vostra configurazione iniziale pronta a partire, e installare tutti i pacchetti necessari. Lo switch --style=scss è opzionale e imposterà il compilatore per compilare i file SCSS in CSS, di cui avremo bisogno in seguito.

Una volta che l’installazione è completa, puoi cd my-memories ed eseguire ng serve. Questo avvierà il processo di costruzione e un server web locale che servirà la tua app a http://localhost:4200.

Un'app Angular 6 subito dopo lo scaffolding

Quello che succede dietro le quinte è che la CLI traspila tutti i .ts (file TypeScript) in vanilla JS, raccoglie tutte le dipendenze necessarie dalla cartella dei pacchetti node_modules, e produce il risultato in un insieme di file che vengono serviti tramite un server web locale che gira sulla porta 4200.

File del progetto

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

La struttura delle cartelle del progetto Angular 6

Initial Setup

Ok, finora abbiamo la configurazione iniziale della nostra app. Iniziamo a fare qualche cambiamento.

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 un po’ di HTML di base e il tag <app-root>. Questo è un componente Angular, e dove Angular 6 inserisce il codice del nostro componente.

Troveremo il file app/app.component.ts, che ha il selettore app-root che corrisponde 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 rendere e quali fogli di stile usare.

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

Se guardiamo a app.component.html vedremo il binding di interpolazione {{title}}. Qui è dove avviene tutto il binding magico, e Angular renderà il valore della proprietà title della classe e lo aggiornerà ogni volta che cambia.

<!--The content below is only a placeholder and can be replaced.--><div style="text-align:center"> <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 dalla classe a 'My Memories!'.

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

Vedremo il compilatore elaborare la nostra modifica e il browser aggiornarsi per mostrare il nostro titolo aggiornato.

Questo significa che il ng serve di Angular 6 osserva i cambiamenti del nostro file e fa il rendering ogni volta che viene introdotto un cambiamento in qualsiasi file.

Per rendere la codifica più amichevole ed evitare il refresh completo della pagina ogni volta che facciamo delle modifiche, possiamo sfruttare l’Hot Module Replacement (HMR) di webpack, che aggiorna solo il pezzo di JS/CSS che è stato cambiato invece di produrre un refresh completo per mostrare le modifiche.

Configurare HMR

Per prima cosa, dobbiamo impostare l’ambiente.

Crea un file src/environments/environment.hmr.ts con il seguente contenuto:

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

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

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

Poi aggiorna src/environments/environment.ts e aggiungi anche lì il flag hmr: false all’ambiente:

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

Poi nel file angular.json, aggiorna questa parte:

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

E sotto projectsmy-memoriesarchitectserveconfigurations:

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

Ora aggiorna tsconfig.app.json per includere il necessario types (beh, il tipo) aggiungendo questo sotto compilerOptions:

 "compilerOptions": { // ... "types": 

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

npm install --save-dev @angularclass/hmr

Poi lo configuriamo 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(); });};

Poi aggiorniamo src/main.ts per usare la funzione di cui sopra:

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) { 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 è far chiamare a 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 abilitato la sostituzione del modulo a caldo; altrimenti, facciamo il bootstrap come eravamo soliti fare.

Ora, quando eseguiamo ng serve --hmr --configuration=hmr, invochiamo la configurazione hmr, e quando facciamo modifiche ai file, otterremo aggiornamenti senza un refresh completo. Il primo --hmr è per webpack, e --configuration=hmr è per Angular per usare l’ambiente hmr.

Progressive Web App (PWA)

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

ng add @angular/

Nota che sto aggiungendo la versione, poiché l’ultima versione quando stavo scrivendo questo tutorial stava dando un errore. (Potete provare senza e controllare se funziona per voi usando semplicemente ng add @angular/pwa.)

Ok, quindi dopo aver eseguito il comando vedremo molti cambiamenti nel nostro progetto. I cambiamenti più importanti sono che ha aggiunto:

  • Un riferimento a manifest.json nel file angular.json delle risorse, 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 mettere in cache tutti i file necessari all’app per funzionare
  • Un meta tag manifest.json nel file index.html
  • Lo stesso file manifest.json, con una configurazione di base per l’app
  • Il carico del service worker nel modulo dell’app ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production }) (notare che il service worker sarà abilitato solo in ambienti di produzione)

Quindi, questo significa che quando l’utente accede per la prima volta all’URL, i file saranno scaricati. Dopo di che, se l’utente tenta di accedere all’URL senza servizio di rete, l’app funzionerà ancora estraendo quei file dalla cache.

Aggiungi la libreria Material Angular 6 UI

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

Per installare il pacchetto material sulla nostra app, faremo di nuovo uso di ng add:

ng add @angular/material

Dopo averlo eseguito, vedremo alcuni nuovi pacchetti aggiunti e qualche configurazione di stile di base:

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

Indica la tua scelta di un tema Angular 6 precostruito

Devi riavviare ng serve per prendere il tema, oppure puoi scegliere un altro tema precostituito.

Correlato: Costruire Web Apps ultramoderne con Angular Material

Layout di base

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

(In poche parole, gli schemi ti permettono di applicare trasformazioni a un progetto: Puoi creare, modificare o cancellare i file secondo necessità. In questo caso, impagina 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 appena creato "my-nav"

Siccome stiamo usando SCSS, dobbiamo rinominare il file my-nav.component.css in my-nav.component.scss, e in my-nav.component.ts aggiornare il riferimento corrispondente styleUrls per utilizzare il nuovo nome.

Ora per fare uso del nuovo componente, andiamo in 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 pannelli con Menu nell'angolo in alto a sinistra, i miei ricordi accanto, e tre link numerati sotto Menu; il quarto pannello è vuoto

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

Prima di tutto, creiamo due nuovi componenti:

ng g c AddMemoryng generate @angular/material:material-table --name=view-memories

(Il secondo è uno schema Materiale usato per creare una tabella.)

Poi, su my-nav 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" ="(isHandset$ | async) ? 'dialog' : 'navigation'" ="(isHandset$ | async) ? 'over' : 'side'" ="!(isHandset$ | async)"> <mat-toolbar color="primary">Menu</mat-toolbar> <mat-nav-list> <a mat-list-item ="">Add Memory</a> <a mat-list-item ="">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 <router-outlet> principale (cioè, rimuovere <my-nav>):

<router-outlet></router-outlet>

Poi, nel AppModule includeremo le rotte:

import { RouterModule, Routes } from '@angular/router';// ...imports: }, ]),]

Nota che stiamo impostando MyNavComponent come genitore e i due componenti che abbiamo creato come figli. Questo perché abbiamo incluso il <router-outlet> in MyNavComponent, e ogni volta che colpiremo una di queste due rotte, renderizzeremo il componente figlio dove è stato inserito il <router-outlet>.

Dopo questo, quando serviremo l’applicazione dovremmo vedere:

I link di sinistra sono stati sostituiti con Add Memory e View My Memories, con quest'ultimo selezionato. Il pannello vuoto ora ha una tabella con numeri id e nomi.

Costruisci l’app (Un diario dei ricordi)

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

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

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

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

<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..." ="memory.date" name="date" ="date"> <mat-datepicker-toggle matSuffix ="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 ="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 un mat-card e aggiungendo due campi, un date e un textarea.

Nota che stiamo usando . Questa direttiva Angular legherà l’espressione memory.date e la proprietà memory nella classe, come vedremo più avanti. ( è uno zucchero sintattico, una scorciatoia per eseguire il data binding bidirezionale dalla classe alla vista e dalla vista alla classe. Questo significa che quando si inserisce del testo nella vista, memory.date rifletterà quei cambiamenti nell’istanza della classe, e se si fanno dei cambiamenti a memory.date nell’istanza della classe, la vista rifletterà i cambiamenti.

Nella add-memory.component.ts, il codice sarà come questo:

import { Component, OnInit } from '@angular/core';@Component({ selector: 'app-add-memory', templateUrl: './add-memory.component.html', styleUrls: })export class AddMemoryComponent implements OnInit { memory: any = {}; constructor() { } ngOnInit() { } onSubmit() { console.log(this.memory); }}

Qui, stiamo inizializzando la proprietà memory legata tramite ngModel. Quando il componente AddMemoryComponent viene istanziato, memory sarà un oggetto vuoto. Poi, quando la direttiva ngModel viene eseguita, 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.

Mentre, add-memory.component.scss deve avere:

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

Siccome abbiamo <pre> {{ memory | json }} </pre> possiamo vedere lo stato attuale di memory nella vista. Se andiamo nel browser, ecco il risultato finora:

Il prototipo dell

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

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

Così, quando si fa clic sul pulsante “Salvami!”, si ottiene la rappresentazione interna dell’input dell’utente inviata al log della console:

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

Angular 6 Tutorial: Connettersi con Firebase

Quello che faremo ora è connettere il nostro progetto a Firebase per salvare le nostre memorie.

Prima di tutto, andremo alla console Firebase e creeremo un progetto lì.

Aggiungere un progetto Firebase.

In secondo luogo, installeremo i pacchetti firebase e angularfire2:

npm install firebase angularfire2 --save

E poi in ognuno 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 cliccando su “Aggiungi Firebase alla tua web app” nella pagina di panoramica del progetto.

Dopo di che, includeremo i moduli Firebase nel nostro app.module.ts:

import { AngularFireModule } from 'angularfire2';import { AngularFireDatabaseModule } from 'angularfire2/database';import { environment } from '../environments/environment';// ...Imports:

E in add-memory.component.ts, iniettiamo il database nel costruttore e salviamo i valori dal modulo al database. Quando la promessa di push da Firebase ha successo, registriamo il successo nella console e resettiamo 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 tuo database Firebase.

Avrai bisogno di consentire l’accesso pubblico alle regole del database, così gli utenti anonimi possono leggere e scrivere. Si prega di notare che con questa configurazione, qualsiasi utente sarebbe in grado di leggere/modificare/cancellare i dati dell’applicazione. Assicurati di impostare le tue regole di conseguenza prima di andare in produzione.

Inoltre, per prendere le modifiche all’ambiente dovrai riavviare il processo ng serve.

Ora, quando torneremo al browser e cliccheremo 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 Material.

Poi 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 fasulli, quindi dovremo cambiarlo per iniziare a prelevare da Firebase.

In view-memories-datasource.ts, rimuoveremo il 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 a date e text dal nostro modello di memoria. Notate che siccome abbiamo salvato la data in formato millisecondi, qui stiamo usando una pipe data per trasformare il valore per la visualizzazione in un formato data più umano. Infine rimuoviamo il ="dataSource.data.length" dal paginatore, poiché caricheremo i dati in modo asincrono da Firebase:

<div class="mat-elevation-z8"> <table mat-table #table ="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 ="0" ="50" =""> </mat-paginator></div>

Cambiamo il view-memories.component.css in view-memories.component.scss e impostiamo lo stile della tabella:

table{ width: 100%;}

In view-memories.component.ts, cambieremo il styleUrls per riflettere la rinomina di cui sopra in ./view-memories.component.scss. Aggiorneremo anche l’array displayedColumns per essere e configureremo la tabella datasource per ottenere i dati da Firebase.

Quello che sta succedendo qui è che ci stiamo abbonando alla lista delle memorie e quando riceviamo i dati istanziamo la 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 Observable in stile ReactiveX.

Nota che stiamo lanciando this.db.list<ViewMemoriesItem>('memories')i valori estratti dal percorso 'memories' in ViewMemoriesItem. Di questo si occupa la libreria angularfire2.

Abbiamo anche incluso la chiamata unsubscribe all’interno dell’hook 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: })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 = ; 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(); }}

Deploy su Firebase Hosting

Ora, per rendere la nostra app attiva, facciamo il deploy su Firebase Hosting. Per questo, installeremo Firebase CLI, 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.

Prossimo, inizializzeremo il progetto e configureremo Firebase Hosting:

firebase init

Selezioneremo semplicemente l’opzione Hosting.

Prossimo, quando ci verrà chiesto il percorso, lo impostiamo su dist/my-memories. Quando ci viene chiesto se configurarlo come un’app a pagina singola (cioè riscrivere tutti gli URL a /index.html), risponderemo “sì”.”

Infine, colpiremo: “Il file dist/my-memories/index.html esiste già. Sovrascrivere?” Qui diremo “no”.

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

L’ultimo passo è quello di eseguire:

ng build --prodfirebase deploy

E con questo, avremo pubblicato l’app su Firebase, che ci fornisce un URL a cui navigare, come https://my-memories-b4c52.firebaseapp.com/view-memories, dove potete vedere la mia demo pubblicata.

Wow, avete finito il tutorial! Spero che vi sia piaciuto. Puoi anche controllare il codice completo su GitHub.

Un passo alla volta

Angular è un framework molto potente per costruire applicazioni web. È in circolazione da molto tempo e si è dimostrato valido sia per le app piccole e semplici che per quelle grandi e complesse – Angular 6 non fa eccezione.

In futuro, Angular prevede di continuare a migliorare e seguire nuovi paradigmi web come i componenti web (Angular Elements). Se sei interessato a costruire app ibride, puoi dare un’occhiata a Ionic, che usa Angular come framework sottostante.

Questo tutorial ha coperto i passi molto semplici per iniziare a usare Angular, Material e Firebase. Ma dovreste considerare che per le applicazioni del mondo reale, avrete bisogno di aggiungere la validazione, e per rendere la vostra applicazione più facile da mantenere e scalare, probabilmente vorrete seguire le migliori pratiche come l’utilizzo di servizi, componenti riutilizzabili, ecc. Questo dovrà essere l’argomento di un altro articolo – speriamo che questo sia stato sufficiente a stuzzicare il vostro appetito per lo sviluppo Angular! Tutti i vantaggi, nessuna seccatura: Un tutorial su Angular 9 .

Leave a Reply