Tutorial Angular 6: Caracteristici noi cu putere nouă
Publicat: 2022-03-11Angular 6 a ieșit! Cele mai remarcabile modificări sunt în CLI-ul său și în modul în care serviciile sunt injectate. Dacă doriți să scrieți prima dvs. aplicație Angular 6 - sau aplicația Angular/Firebase - în acest tutorial, vom trece peste pașii de bază ai configurării inițiale și vom crea o mică aplicație de jurnal.
Angular 6: Elementele de bază
Dacă nu ați mai folosit niciodată Angular, permiteți-mi să vă fac o scurtă descriere a acestuia și a modului în care funcționează.
Angular este un cadru JavaScript conceput pentru a sprijini construirea de aplicații cu o singură pagină (SPA) atât pentru desktop, cât și pentru mobil.
Cadrul include o suită completă de directive și module care vă permit să implementați cu ușurință unele dintre cele mai comune scenarii pentru o aplicație web, cum ar fi navigarea, autorizarea, formularele și raportarea. De asemenea, vine cu toate pachetele necesare pentru a adăuga teste folosind framework-ul Jasmine și a le rula folosind rulații de testare Karma sau Protractor.
Arhitectura unghiulară se bazează pe componente, șabloane, directive și servicii. Acesta oferă un mecanism de injectare a dependenței încorporat pentru serviciile dvs., precum și legare bidirecțională a datelor pentru a vă conecta vizualizările cu codul componentei.
Angular folosește TypeScript, un superset tip JS, și va face unele lucruri mai ușoare, mai ales dacă veniți dintr-un fundal de limbaj tastat.
Angular 6: Caracteristici noi
Un scurt rezumat al noilor funcții din Angular 6:
- O politică de sincronizare a numerelor majore de versiune pentru pachetele cadru (
@angular/core
,@angular/common
,@angular/compiler
, etc.), CLI, Material și CDK. Acest lucru va ajuta la clarificarea compatibilității încrucișate în viitor: puteți spune dintr-o privire rapidă la numărul versiunii dacă pachetele de chei sunt compatibile între ele. - Noi comenzi
ng
CLI:-
ng update
pentru a actualiza inteligent versiunile pachetelor, actualizând versiunile dependențelor și păstrându-le sincronizate. (De exemplu, când rulațing update @angular/core
, toate cadrele vor fi actualizate, precum și RxJS.) Va rula și scheme dacă pachetul le include. (Dacă o versiune mai nouă include modificări care necesită modificări ale codului, schema vă va actualiza codul.) -
ng add
pentru a adăuga pachete noi (și rulați scripturi, dacă este cazul)
-
- Serviciile fac referire acum la modulele care le vor furniza, în loc de modulele care fac referire la servicii, așa cum le aveau înainte.
Ca exemplu a ceea ce înseamnă această ultimă modificare, unde arăta codul dvs.:
@NgModule({ // ... providers: [MyService] })
… cu această schimbare specială în Angular 6, va arăta astfel:
@Injectabe({ providedIn: 'root', })
Aceștia se numesc furnizori tree-shakeable și permit compilatorului să elimine servicii fără referință, rezultând pachete de dimensiuni mai mici.
Angular 6 CLI
Interfața de linie de comandă ng
este o piesă foarte importantă a Angular și vă permite să vă mișcați mai rapid atunci când vă codificați aplicația.
Cu ajutorul CLI, puteți configura foarte ușor configurația inițială a aplicației, puteți genera noi componente, directive etc. și puteți construi și rula aplicația în mediul dvs. local.
Crearea unui proiect Angular 6
Bine, destulă vorbă. Să ne murdărim mâinile și să începem să codificăm.
Pentru a începe, veți avea nevoie de Node.js și npm instalate pe computer.
Acum, să mergem mai departe și să instalăm CLI:
npm install -g @angular/cli
Aceasta va instala comanda ng
CLI la nivel global, datorită comutatorului -g
.
Odată ce avem asta, putem obține schela inițială pentru aplicația noastră cu ng new
:
ng new my-memories --style=scss
Aceasta va crea un folder my-memories
, va crea toate fișierele necesare pentru a pregăti configurarea inițială pentru a începe și va instala toate pachetele necesare. --style=scss
este opțional și va configura compilatorul pentru a compila fișiere SCSS în CSS, de care vom avea nevoie mai târziu.
Odată ce instalarea este finalizată, puteți să cd my-memories
și să rulați ng serve
. Acest lucru va începe procesul de construire și un server web local care deservește aplicația dvs. la http://localhost:4200
.
Ceea ce se întâmplă în culise este că CLI transpilează toate fișierele .ts
(fișiere TypeScript) în vanilla JS, adună toate dependențele necesare din folderul de pachete node_modules
și redă rezultatul într-un set de fișiere care sunt servite printr-un server web local. care rulează pe portul 4200.
Fișiere de proiect
Dacă nu sunteți familiarizat cu structura folderului de proiect din Angular, cel mai important lucru pe care trebuie să-l știți este că tot codul legat de aplicație intră în folderul src
. De obicei, veți crea toate modulele și directivele în acel folder, urmând arhitectura aplicației (de exemplu, utilizator, coș, produs.)
Configurare inițială
Bine, până acum avem configurarea inițială pentru aplicația noastră. Să începem să facem câteva modificări.
Înainte de a începe, să pătrundem puțin în folderul src
. Pagina inițială este 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>
Aici vedem câteva coduri HTML de bază și eticheta <app-root>
. Aceasta este o componentă Angular și unde Angular 6 inserează codul nostru de componentă.
Vom găsi fișierul app/app.component.ts
, care are selectorul app-root
pentru a se potrivi cu ceea ce este în fișierul index.html
.
Componenta este o clasă TypeScript decorată și, în acest caz, conține proprietatea title
. Decoratorul @Component
îi spune lui Angular să includă comportamentul componentei în clasă. În plus față de selector, specifică ce fișier HTML să fie randat și ce foi de stil să folosească.
import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent { title = 'app'; }
Dacă ne uităm la app.component.html
, vom vedea legarea de interpolare {{title}}
. Aici se întâmplă toată legarea magică, iar Angular va reda valoarea proprietății titlului clasei și o va actualiza de fiecare dată când se schimbă.
<!--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>
Să mergem mai departe și să actualizăm title
din clasă la 'My Memories!'
.
... export class AppComponent { title = 'My Memories!'; } ...
Vom vedea cum compilatorul procesează modificarea noastră și reîmprospătează browserul pentru a afișa titlul nostru actualizat.
Aceasta înseamnă că Angular 6 ng serve
ceasuri pentru modificările fișierelor noastre și se redă de fiecare dată când o modificare este introdusă în orice fișier.
Pentru a face codarea mai prietenoasă și pentru a evita reîmprospătarea completă a paginii de fiecare dată când facem modificări, putem profita de Webpack Hot Module Replacement (HMR), care actualizează doar porțiunea de JS/CSS care a fost schimbată în loc să producă o reîmprospătare completă la arată modificările tale.
Configurarea HMR
În primul rând, trebuie să creăm mediul.
Creați un fișier src/environments/environment.hmr.ts
cu următorul conținut:
export const environment = { production: false, hmr: true };
Actualizați src/environments/environment.prod.ts
și adăugați hmr: false
flag la mediu:
export const environment = { production: true, hmr: false };
Apoi actualizați src/environments/environment.ts
și adăugați și hmr: false
flag la mediu acolo:
export const environment = { production: false, hmr: false };
În continuare, în fișierul angular.json
, actualizați această parte:
"projects": { "my-memories": { // ... "architect": { "build": { // ... "configurations": { "hmr":{ "fileReplacements":[ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.hmr.ts" } ] }, // ...
Și sub projects
→ my-memories
→ architect
→ serve
→ configurations
:
"projects": { "my-memories": { "architect": { // ... "serve": { // ... "configurations": { "hmr": { "browserTarget": "my-memories:build:hmr" }, // ...
Acum actualizați tsconfig.app.json
pentru a include types
necesare (ei bine, tastați) adăugând acest lucru sub compilerOptions
:
"compilerOptions": { // ... "types": [ "node" ]
În continuare, vom instala @angularclass/hmr
ca dependență de dezvoltare:
npm install --save-dev @angularclass/hmr
Apoi configurați-l prin crearea unui fișier 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(); }); };
Apoi, actualizați src/main.ts
pentru a utiliza funcția de mai sus:
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)); }
Ceea ce facem aici este să facem apelul bootstrap să fie o funcție anonimă și apoi să întrebăm dacă indicatorul environment.hmr
este adevărat. Dacă este, apelăm funcția definită anterior din hmr.ts
care a permis înlocuirea la cald a modulului; în caz contrar, îl pornim așa cum obișnuiam.
Acum, când rulăm ng serve --hmr --configuration=hmr
, vom invoca configurația hmr
, iar când vom face modificări la fișiere, vom primi actualizări fără o reîmprospătare completă. Primul --hmr
este pentru webpack și --configuration=hmr
este pentru Angular să folosească mediul hmr
.
Aplicație web progresivă (PWA)
Pentru a adăuga suport pentru Angular 6 PWA și pentru a activa încărcarea offline pentru aplicație, putem folosi una dintre noile comenzi CLI, ng add
:
ng add @angular/[email protected]
Rețineți că adaug versiunea, deoarece cea mai recentă versiune când scriam acest tutorial prezenta o eroare. (Puteți încerca fără el și verificați dacă funcționează pentru dvs. folosind pur și simplu ng add @angular/pwa
.)
Bine, așa că după ce vom rula comanda, vom vedea o mulțime de modificări în proiectul nostru. Cele mai importante modificări sunt că a adăugat:
- O referință la
manifest.json
în fișierul de activeangular.json
, astfel încât să fie inclus în rezultatul build-ului, precum și"serviceWorker": true
în versiunile de producție - Fișierul
ngsw-config.json
cu configurarea inițială pentru a stoca în cache toate fișierele necesare pentru rularea aplicației - O metaetichetă
manifest.json
în fișierulindex.html
- Fișierul
manifest.json
în sine, cu o configurație de bază pentru aplicație - Încărcarea lucrătorului de service în modulul de aplicație
ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production })
(rețineți că lucrătorul de service va fi activat numai în mediile de producție)
Deci, aceasta înseamnă că atunci când utilizatorul accesează pentru prima dată adresa URL, fișierele vor fi descărcate. După aceea, dacă utilizatorul încearcă să acceseze adresa URL fără serviciu de rețea, aplicația va funcționa în continuare prin extragerea acelor fișiere din cache.
Adăugarea bibliotecii Material Angular 6 UI
Până acum avem configurația inițială și suntem gata să începem construirea aplicației noastre. Pentru a folosi componentele deja construite, putem folosi versiunea Angular 6 a Material.
Pentru a instala pachetul de material
în aplicația noastră, vom folosi din nou ng add
:
ng add @angular/material
După ce vom rula asta, vom vedea câteva pachete noi adăugate și o configurație de bază a stilului:
-
index.html
include fontul Roboto și pictogramele Material -
BrowserAnimationsModule
este adăugat laAppModule
-
angular.json
are deja inclusă tema indigo-roz pentru noi
Va trebui să reporniți ng serve
pentru a prelua tema sau puteți alege o altă temă predefinită.
Aspect de bază
Pentru a avea aspectul sidenav inițial, vom folosi schemele care vin cu Material. Dar este în regulă dacă doriți să utilizați un aspect diferit.
(Pe scurt, schemele vă permit să aplicați transformări unui proiect: puteți să creați, să modificați sau să ștergeți fișiere după cum este necesar. În acest caz, schelele un aspect sidenav pentru aplicația noastră.)
ng generate @angular/material:material-nav --name=my-nav
Aceasta va crea o componentă sidenav cu configurarea minimă gata de pornire. Nu este grozav?
De asemenea, a inclus toate modulele necesare în app.module.ts
.
Deoarece folosim SCSS, trebuie să redenumim fișierul my- my-nav.component.css
în my-nav.component.scss
, iar în my-nav.component.ts
actualizăm styleUrls
de referință corespunzătoare pentru a utiliza noul nume.
Acum, pentru a folosi noua componentă, să mergem la app.component.html
și să eliminăm tot codul inițial, lăsând doar:
<app-my-nav></app-my-nav>
Când ne întoarcem la browser, iată ce vom vedea:
Să actualizăm linkurile pentru a avea doar cele două opțiuni pe care le dorim.
Mai întâi, să creăm două componente noi:
ng gc AddMemory ng generate @angular/material:material-table --name=view-memories
(A doua este o schemă de material folosită pentru a crea un tabel.)
Apoi, pe my-nav
ne vom actualiza pentru a configura legăturile și vom include <router-outlet>
pentru a afișa componentele noastre de conținut:
<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>
De asemenea, în app.component.html
trebuie să-l actualizăm pentru a avea doar <router-outlet>
principal (adică, eliminați <my-nav>
):

<router-outlet></router-outlet>
În continuare, în AppModule
vom include rutele:
import { RouterModule, Routes } from '@angular/router'; // ... imports: [ // ... RouterModule.forRoot([ { path: '', component: MyNavComponent, children: [ { path: 'add-memory', component: AddMemoryComponent }, { path: 'view-memories', component: ViewMemoriesComponent } ] }, ]), ]
Rețineți că MyNavComponent
ca părinte și cele două componente pe care le-am creat ca copii. Acest lucru se datorează faptului că am inclus <router-outlet>
în MyNavComponent
și de fiecare dată când atingem una dintre aceste două rute, vom reda componenta copil în care a fost plasat <router-outlet>
.
După aceasta, când servim aplicația, ar trebui să vedem:
Creați aplicația (A Memories Diary)
Bine, acum să creăm formularul pentru a salva noi amintiri în jurnalul nostru.
Va trebui să importăm câteva module de materiale și modulul de formulare în app.module.ts
:
import { FormsModule } from '@angular/forms'; import { MatCardModule, MatFormFieldModule, MatInputModule, MatDatepickerModule, MatNativeDateModule } from '@angular/material'; // ... Imports:[ // ... MatCardModule, MatFormFieldModule, MatInputModule, MatDatepickerModule, FormsModule, MatNativeDateModule, // ... ]
Și apoi în add-memory.component.html
, vom adăuga forma:
<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>
Aici folosim un mat-card
și adăugăm două câmpuri, o date
și o zonă de textarea
.
Rețineți că folosim [(ngModel)]
. Această directivă Angular va lega expresia memory.date
și proprietatea memory
din clasă una de cealaltă, așa cum vom vedea mai târziu. ( [(ngModel)]
este zahăr sintactic — o comandă rapidă pentru a efectua legături bidirecționale de date de la clasă la vizualizare și de la vizualizare la clasă. Aceasta înseamnă că atunci când introduceți text în vizualizare, memory.date
va reflecta acele modificări în instanța de clasă și dacă faceți modificări la memory.date
în instanța de clasă, vizualizarea va reflecta modificările.)
În add-memory.component.ts
, codul va arăta astfel:
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); } }
Aici, inițializam proprietatea memory
legată de ngModel
. Când componenta AddMemoryComponent
este instanțiată, memory
va fi un obiect gol. Apoi, când se rulează directiva ngModel
, va putea atribui valoarea de intrare memory.date
și memory.text
. Dacă nu am face acest lucru, vom primi o eroare de Cannot set property 'date/text' of undefined
.
Între timp, add-memory.component.scss
trebuie să aibă:
.memory-card { min-width: 150px; max-width: 400px; width: 100%; margin: auto; } .mat-form-field { width: 100%; }
Deoarece avem <pre> {{ memory | json }} </pre>
<pre> {{ memory | json }} </pre>
putem vedea starea curentă a memory
în vizualizare. Dacă mergem la browser, iată rezultatul de până acum:
În vizualizare, am legat formularul prin (ngSubmit)="onSubmit()"
la funcția onSubmit
din clasă.
onSubmit() { console.log(this.memory); }
Deci, când dați clic pe „Salvați-mă!” butonul, veți primi reprezentarea internă a intrării utilizatorului trimisă în jurnalul consolei:
Tutorial Angular 6: Conectarea cu Firebase
Ceea ce vom face în continuare este să ne conectăm proiectul la Firebase pentru a ne salva amintirile.
Mai întâi, vom merge la consola Firebase și vom crea un proiect acolo.
În al doilea rând, vom instala pachetele firebase
și angularfire2
:
npm install firebase angularfire2 --save
Și apoi în fiecare dintre aceste trei fișiere:
-
/src/environments/environment.ts
-
/src/environments/environment.hmr.ts
-
/src/environments/environment.prod.ts
… vom adăuga configurația noastră 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>' } };
Puteți obține detaliile de configurare necesare pentru fișierele de mai sus făcând clic pe „Adăugați Firebase la aplicația dvs. web” pe pagina de prezentare generală a proiectului.
După aceea, vom include modulele Firebase în app.module.ts
:
import { AngularFireModule } from 'angularfire2'; import { AngularFireDatabaseModule } from 'angularfire2/database'; import { environment } from '../environments/environment'; // ... Imports:[ // ... AngularFireModule.initializeApp(environment.firebase), AngularFireDatabaseModule, // ... ]
Și în add-memory.component.ts
, injectăm baza de date în constructor și salvăm valorile din formular în baza de date. Când promisiunea push de la Firebase are succes, înregistrăm succesul în consolă și resetam modelul:
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') }) }
Va trebui să permiteți accesul public la regulile bazei de date, astfel încât utilizatorii anonimi să poată citi și scrie în ea. Vă rugăm să rețineți că, cu această configurare, orice utilizator va putea citi/modifica/șterge datele aplicației dvs. Asigurați-vă că vă configurați regulile în consecință înainte de a trece la producție.
De asemenea, pentru a prelua schimbările de mediu, va trebui să reporniți procesul ng serve
.
Acum, când ne întoarcem la browser și facem clic pe butonul de salvare, vom vedea că memoria a fost adăugată la baza de date:
Să aruncăm o privire la modul în care ne putem recupera amintirile și le putem afișa în tabelul Material.
Când am creat tabelul folosind ng generate @angular/material:material-table --name=view-memories', we automatically got a file
view-memories/view-memories-datasource.ts`. Acest fișier conține date false, așa că va trebui să-l modificăm pentru a începe extragerea din Firebase.
În view-memories-datasource.ts
, vom elimina EXAMPLE_DATA
și vom seta o matrice goală:
export class ViewMemoriesDataSource extends DataSource<ViewMemoriesItem> { data: ViewMemoriesItem[] = []; // ...
Și în getSortedData
vom actualiza numele câmpurilor:
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; } }); }
În view-memories.component.html
vom actualiza numele coloanelor la date
și text
din modelul nostru de memorie. Rețineți că, deoarece am salvat data în format de milisecunde, aici folosim un canal de dată pentru a transforma valoarea pentru afișare într-un format de dată mai prietenos cu oamenii. În cele din urmă, eliminăm [length]="dataSource.data.length"
din paginator, deoarece vom încărca datele asincron din 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>
Schimbați view-memories.component.css
în view-memories.component.scss
și setați stilul tabelului:
table{ width: 100%; }
În view-memories.component.ts
, vom schimba styleUrls
pentru a reflecta redenumirea de mai sus în ./view-memories.component.scss
. De asemenea, vom actualiza matricea displayedColumns
pentru a fi ['date', 'text']
și vom configura sursa de date din tabel pentru a obține date de la Firebase.
Ceea ce se întâmplă aici este că ne abonam la lista de memorii și când primim datele, instanțiăm ViewMemoriesDataSource
și setăm proprietatea de date cu datele din 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 returnează o matrice Observable în stil ReactiveX.
Rețineți că this.db.list<ViewMemoriesItem>('memories')
— valorile extrase din calea 'memories'
— în ViewMemoriesItem
. Acest lucru este îngrijit de biblioteca angularfire2
.
Am inclus și apelul de unsubscribe
în hook-ul onDestroy
al ciclului de viață al componentei 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(); } }
Implementare pe Firebase Hosting
Acum, pentru a face aplicația noastră live, să o implementăm pe Firebase Hosting. Pentru aceasta, vom instala CLI-ul Firebase, care face disponibilă comanda firebase
:
npm install -g firebase-tools
Acum putem folosi Firebase CLI pentru a vă conecta:
firebase login
Acest lucru vă va solicita să vă selectați contul Google.
În continuare, vom inițializa proiectul și vom configura Firebase Hosting:
firebase init
Vom selecta doar opțiunea Gazduire.
Apoi, când ni se cere calea, o vom seta la dist/my-memories
. Când suntem întrebați dacă o configuram ca aplicație cu o singură pagină (adică rescriem toate adresele URL în /index.html
), vom răspunde „da”.
În cele din urmă, vom apăsa „File dist/my-memories/index.html deja există. Suprascrie?” Aici vom spune „nu”.
Aceasta va crea fișierele de configurare Firebase .firebaserc
și firebase.json
cu configurația furnizată.
Ultimul pas este să rulați:
ng build --prod firebase deploy
Și cu asta, vom fi publicat aplicația în Firebase, care oferă o adresă URL la care să navigăm, cum ar fi https://my-memories-b4c52.firebaseapp.com/view-memories, unde puteți vedea propria mea publicată demonstrație.
Wow, ai trecut prin tutorial! Sper ca ti-a placut. De asemenea, puteți consulta codul complet al acestuia pe GitHub.
Cu pasi marunti
Angular este un cadru foarte puternic pentru construirea de aplicații web. A existat de mult timp și s-a dovedit atât pentru aplicațiile mici, simple, cât și pentru cele mari și complexe — Angular 6 nu face excepție aici.
În continuare, Angular intenționează să continue să se îmbunătățească și să urmeze noi paradigme web, cum ar fi componentele web (Angular Elements). Dacă sunteți interesat să construiți aplicații hibride, puteți verifica Ionic, care folosește Angular ca cadru de bază.
Acest tutorial a acoperit pașii de bază pentru a începe să utilizați Angular, Material și Firebase. Dar ar trebui să țineți cont de faptul că, pentru aplicațiile din lumea reală, va trebui să adăugați validare și, pentru a face aplicația mai ușor de întreținut și scalat, probabil că ați dori să urmați cele mai bune practici, cum ar fi utilizarea Serviciilor, a componentelor reutilizabile etc. Acesta va trebui să facă obiectul unui alt articol - sperăm că acesta a fost suficient pentru a vă stârni apetitul pentru dezvoltarea Angular!