Angular 6 Tutorial: Nya funktioner med ny kraft

Angular 6 är ute! De mest framträdande förändringarna finns i dess CLI och hur tjänster injiceras. Om du vill skriva din allra första Angular 6-app – eller Angular/Firebase-app – i den här handledningen går vi igenom de grundläggande stegen för den första installationen och skapar en liten dagboksapp.

Angular 6: Grunderna

Om du aldrig har använt Angular tidigare ska jag ge dig en kort beskrivning av det och hur det fungerar.

Angular är ett JavaScript-ramverk som är utformat för att stödja byggandet av enkelsidiga applikationer (SPA:s) för både datorer och mobiler.

Ramenverket innehåller en hel uppsättning direktiv och moduler som gör att du enkelt kan implementera några av de vanligaste scenarierna för en webbapplikation, som navigering, auktorisering, formulär och rapportering. Det levereras också med alla nödvändiga paket för att lägga till tester med hjälp av ramverket Jasmine och köra dem med testkörarna Karma eller Protractor.

Angular-arkitekturen är baserad på komponenter, mallar, direktiv och tjänster. Den tillhandahåller en inbyggd mekanism för injektion av beroenden för dina tjänster samt tvåvägsdatabindning för att koppla ihop dina vyer med din komponentkod.

Angular använder TypeScript, en typad överordning av JS, och kommer att göra vissa saker enklare, särskilt om du kommer från en bakgrund med typade språk.

Angular 6: Nya funktioner

En kort sammanfattning av de nya funktionerna i Angular 6:

  • En policy för att synkronisera de större versionsnumren för rampaketen (@angular/core, @angular/common, @angular/compiler osv.), CLI, Material och CDK. Detta kommer att bidra till att göra korskompatibiliteten tydligare framöver: Du kan med en snabb titt på versionsnumret se om nyckelpaketen är kompatibla med varandra.
  • Nya ng CLI-kommandon:
    • ng update för att uppgradera paketversioner på ett smart sätt, uppdatera versioner av beroenden och hålla dem synkroniserade. (T.ex. när du kör ng update @angular/core kommer alla ramverk att uppdateras liksom RxJS.) Det kommer också att köra scheman om paketet innehåller dem. (Om en nyare version innehåller brytande ändringar som kräver ändringar i koden kommer schemat att uppdatera koden åt dig.)
    • ng add för att lägga till nya paket (och köra skript, om tillämpligt)
  • Tjänster hänvisar nu till de moduler som kommer att tillhandahålla dem, i stället för att moduler hänvisar till tjänster, som de brukade ha det.

Som exempel på vad den här sista ändringen innebär, där din kod brukade se ut som:

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

…med den här ändringen i Angular 6 kommer den att se ut som:

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

Dessa kallas tree-shakeable providers och gör det möjligt för kompilatorn att ta bort tjänster som inte hänvisas till, vilket resulterar i mindre stora buntar.

Angular 6 CLI

Samtalsgränssnittet ng är en mycket viktig del av Angular och gör att du kan gå snabbare fram när du kodar din app.

Med CLI:t kan du mycket enkelt bygga upp din initiala app-installation, generera nya komponenter, direktiv etc. och bygga och köra din app i din lokala miljö.

Skapa ett Angular 6-projekt

Okej, nog med prat. Låt oss få våra händer smutsiga och börja koda.

För att börja behöver du Node.js och npm installerade på din maskin.

Nu ska vi gå vidare och installera CLI:

npm install -g @angular/cli

Detta kommer att installera ng CLI-kommandot globalt, på grund av -g-switchen.

När vi har det kan vi få den initiala ställningen för vår app med ng new:

ng new my-memories --style=scss

Detta kommer att skapa en my-memories mapp, skapa alla nödvändiga filer för att få den initiala inställningen redo att starta och installera alla nödvändiga paket. Växeln --style=scss är valfri och ställer in kompilatorn så att den kompilerar SCSS-filer till CSS, vilket vi kommer att behöva senare.

När installationen är klar kan du cd my-memories och köra ng serve. Detta kommer att starta byggprocessen och en lokal webbserver som serverar din app på http://localhost:4200.

En Angular 6-app omedelbart efter scaffolding

Det som händer bakom kulisserna är att CLI:et transpellerar alla .ts (TypeScript-filer) till vanilla JS, samlar in alla nödvändiga beroenden från paketmappen node_modules och ger ut resultatet i en uppsättning filer som serveras via en lokal webbserver som körs på port 4200.

Projektfiler

Om du inte är bekant med projektmappstrukturen i Angular är det viktigaste du behöver veta att all kod som rör appen hamnar i mappen src. Du kommer vanligtvis att skapa alla dina moduler och direktiv i den mappen efter din apparkitektur (t.ex. användare, kundvagn, produkt.)

Projektmappstrukturen för Angular 6

Initial Setup

Okej, så här långt har vi den initiala installationen för vår app. Låt oss börja göra några ändringar.

Innan vi börjar ska vi gräva lite i mappen src. Den första sidan är 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>

Här ser vi lite grundläggande HTML och taggen <app-root>. Detta är en Angular-komponent och där Angular 6 infogar vår komponentkod.

Vi hittar filen app/app.component.ts, som har selektorn app-root för att matcha det som finns i filen index.html.

Komponenten är en dekorerad TypeScript-klass och innehåller i det här fallet egenskapen title. Dekoratorn @Component talar om för Angular att inkludera komponentbeteendet i klassen. Förutom selektorn specificerar den vilken HTML-fil som ska renderas och vilka formatmallar som ska användas.

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

Om vi tittar på app.component.html ser vi {{title}} interpolationsbindningen. Det är här som all den magiska bindningen sker, och Angular kommer att rendera värdet av klassens titeleigenskap och uppdatera det varje gång det ändras.

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

Låt oss gå vidare och uppdatera title från klassen till 'My Memories!'.

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

Vi ser kompilatorn bearbeta vår ändring och webbläsaren uppdateras för att visa vår uppdaterade titel.

Detta innebär att Angular 6:s ng serve bevakar våra filändringar och renderar varje gång en ändring införs i en fil.

För att göra kodningen mer användarvänlig och undvika en fullständig uppdatering av sidan varje gång vi gör ändringar kan vi dra nytta av webpack Hot Module Replacement (HMR), som bara uppdaterar den bit av JS/CSS som ändrades istället för att producera en fullständig uppdatering för att visa dina ändringar.

Konfigurera HMR

Först måste vi ställa in miljön.

Skapa en fil src/environments/environment.hmr.ts med följande innehåll:

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

Uppdatera src/environments/environment.prod.ts och lägg till flaggan hmr: false i miljön:

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

Uppdatera sedan src/environments/environment.ts och lägg till flaggan hmr: false i miljön även där:

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

Nästan i angular.json-filen uppdaterar du denna del:

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

Och under projectsmy-memoriesarchitectserveconfigurations:

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

Uppdatera nu tsconfig.app.json för att inkludera den nödvändiga types (nåja, typen) genom att lägga till detta under compilerOptions:

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

Nästan ska vi installera @angularclass/hmr-modulen som ett utvecklingsberoende:

npm install --save-dev @angularclass/hmr

Konfigurera den sedan genom att skapa en fil 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(); });};

Nästan uppdaterar vi src/main.ts för att använda ovanstående funktion:

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

Vad vi gör här är att bootstrap anropar en anonym funktion och frågar sedan om flaggan environment.hmr är sann. Om den är det anropar vi den tidigare definierade funktionen från hmr.ts som aktiverade hot module replacement; i annat fall startar vi bootstrap på samma sätt som tidigare.

När vi kör ng serve --hmr --configuration=hmr anropar vi nu hmr-konfigurationen, och när vi ändrar filer får vi uppdateringar utan en fullständig uppdatering. Den första --hmr är för webpack och --configuration=hmr är för Angular för att använda hmr-miljön.

Progressive Web App (PWA)

För att lägga till Angular 6 PWA-stöd och aktivera offline-laddning för appen kan vi använda oss av ett av de nya CLI-kommandona, ng add:

ng add @angular/

Bemärk att jag lägger till versionen, eftersom den senaste versionen när jag skrev den här handledningen gav ett fel. (Du kan prova utan och kontrollera om det fungerar för dig genom att helt enkelt använda ng add @angular/pwa.)

Okej, så efter att vi har kört kommandot kommer vi att se en hel del förändringar i vårt projekt. De viktigaste förändringarna är att den lagt till:

  • En referens till manifest.json i angular.json-tillgångsfilen, så att den inkluderas i byggutgången, samt "serviceWorker": true i produktionsbyggen
  • Filen ngsw-config.json med den initiala inställningen för att cacha alla filer som är nödvändiga för att appen ska kunna köras
  • En manifest.json-metatag i index.html-filen
  • Den egentliga manifest.json-filen, med en grundläggande konfiguration för appen
  • Tjänstearbetaren laddas i appmodulen ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production }) (observera att tjänstearbetaren endast kommer att aktiveras i produktionsmiljöer)

Detta innebär nu att filerna kommer att hämtas när användaren för första gången går in på URL:en. Efter det, om användaren försöker komma åt URL:n utan nätverkstjänst, kommer appen fortfarande att fungera genom att hämta dessa cachade filer.

Lägga till Material Angular 6 UI-biblioteket

Så långt har vi den initiala inställningen, och vi är redo att börja bygga vår app. För att använda oss av redan byggda komponenter kan vi använda Angular 6-versionen av Material.

För att installera material-paketet på vår app använder vi oss återigen av ng add:

ng add @angular/material

När vi kör det kommer vi att se några nya paket läggas till och en grundläggande stilkonfiguration:

  • index.html innehåller Roboto-teckensnittet och Material-ikoner
  • BrowserAnimationsModule läggs till vår AppModule
  • angular.json har indigo-rosa tema redan inkluderat för oss

Anger ditt val av ett förbyggt Angular 6-tema

Du måste starta om ng serve för att hämta temat, eller så kan du välja ett annat förbyggt tema.

Relaterat: Bygg ultramoderna webbappar med Angular Material

Grundläggande layout

För att få den första sidenav-layouten använder vi de scheman som följer med Material. Men det är okej om du vill använda en annan layout.

(I ett nötskal låter scheman dig tillämpa transformationer på ett projekt: Du kan skapa, ändra eller ta bort filer efter behov. I det här fallet skapar den en sidenav-layout för vår app.)

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

Detta kommer att skapa en sidenav-komponent med minsta möjliga inställning som är redo att starta. Är inte det fantastiskt?

Den har också inkluderat alla nödvändiga moduler i vår app.module.ts.

En nyskapad "my-nav" Angular 6-komponent

Då vi använder SCSS måste vi byta namn på my-nav.component.css-filen till my-nav.component.scss, och i my-nav.component.ts uppdatera motsvarande referens styleUrls för att använda det nya namnet.

Nu för att använda den nya komponenten går vi till app.component.html och tar bort all ursprunglig kod, så att det bara återstår:

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

När vi går tillbaka till webbläsaren är det här vad vi kommer att se:

En layout med fyra rutor med Meny i det övre vänstra hörnet, my-memories bredvid och tre numrerade länkar under Meny; den fjärde rutan är tom

Låt oss uppdatera länkarna så att de bara har de två alternativ vi vill ha.

Först ska vi skapa två nya komponenter:

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

(Den andra är ett materialschema som används för att skapa en tabell.)

Nästan, i my-nav uppdaterar vi för att ställa in länkarna och inkludera <router-outlet> för att visa våra innehållskomponenter:

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

Också i app.component.html måste vi uppdatera den så att den bara har den huvudsakliga <router-outlet> (dvs, ta bort <my-nav>):

<router-outlet></router-outlet>

Nästan i AppModule ska vi inkludera vägarna:

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

Bemärk att vi ställer in MyNavComponent som överordnad och de två komponenterna vi skapat som barn. Detta beror på att vi inkluderade <router-outlet> i MyNavComponent, och när vi träffar en av dessa två rutter kommer vi att rendera barnkomponenten där <router-outlet> placerades.

När vi sedan serverar appen bör vi se:

Länkarna till vänster har bytts ut mot Add Memory (Lägg till minne) och View My Memories (Visa mina minnen), med den senare markerad. Den tomma rutan har nu en tabell med id-nummer och namn.

Bygg appen (En minnesdagbok)

Okej, nu ska vi skapa formuläret för att spara nya minnen i vår dagbok.

Vi måste importera några materialmoduler och formulärmodulen till vår app.module.ts:

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

Och sedan i add-memory.component.html lägger vi till formuläret:

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

Här använder vi en mat-card och lägger till två fält, en date och en textarea.

Bemärk att vi använder . Det här Angular-direktivet binder memory.date-uttrycket och memory-egenskapen i klassen till varandra, vilket vi kommer att se senare. ( är ett syntaktiskt socker – en genväg för att utföra dubbelriktad databindning från klassen till vyn och från vyn till klassen. Detta innebär att när du matar in text i vyn kommer memory.date att återspegla dessa ändringar i klassinstansen, och om du gör ändringar i memory.date i klassinstansen kommer vyn att återspegla ändringarna.)

I add-memory.component.ts kommer koden att se ut så här:

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

Här initialiserar vi egenskapen memory som är bunden via ngModel. När AddMemoryComponent-komponenten installeras kommer memory att vara ett tomt objekt. När ngModel-direktivet sedan körs kommer det att kunna tilldela ingångsvärdet till memory.date och memory.text. Om vi inte skulle göra detta skulle vi få ett fel Cannot set property 'date/text' of undefined.

Men add-memory.component.scss måste ha:

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

Då vi har <pre> {{ memory | json }} </pre> kan vi se det aktuella tillståndet för memory i vyn. Om vi går till webbläsaren ser vi här resultatet hittills:

Prototypen för dagboksappen "my-memories", som visar den interna representationen av användarens inmatning (datum och text.)

I vyn har vi bundit formuläret via (ngSubmit)="onSubmit()" till funktionen onSubmit i klassen.

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

Så när du klickar på knappen ”Save me!” får du den interna representationen av användarinmatningen som skickas till konsolloggen:

Den interna representationen av användarinmatningen i konsolloggen.

Angular 6 Tutorial:

Vad vi ska göra härnäst är att ansluta vårt projekt till Firebase för att spara våra minnen.

Först ska vi gå till Firebase-konsolen och skapa ett projekt där.

Lägga till ett Firebase-projekt.

För det andra installerar vi paketen firebase och angularfire2:

npm install firebase angularfire2 --save

Och sedan i var och en av dessa tre filer:

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

… lägger vi till vår Firebase config:

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

Du kan få de nödvändiga konfigurationsuppgifterna för ovanstående filer genom att klicka på ”Add Firebase to your web app” (Lägg till Firebase i din webbapplikation) på projektöversiktssidan.

Efter det inkluderar vi Firebase-modulerna i vår app.module.ts:

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

Och i add-memory.component.ts injicerar vi databasen i konstruktören och sparar värdena från formuläret till databasen. När push-löftet från Firebase är framgångsrikt loggar vi framgången i konsolen och återställer modellen:

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

Att tillåta läs- och skrivåtkomst till din Firebase-databas.

Du måste tillåta offentlig åtkomst till databasreglerna, så att anonyma användare kan läsa från och skriva till den. Observera att med den här inställningen kan alla användare läsa/ändra/ta bort appens data. Se till att du ställer in dina regler i enlighet med detta innan du går till produktion.

För att hämta miljöförändringarna måste du också starta om ng serve-processen.

När vi nu går tillbaka till webbläsaren och klickar på vår spara-knapp ser vi att minnet lades till i databasen:

Vårt testminne läggs till i vår dagboksapps Firebase-databas.

Vi ska ta en titt på hur vi kan hämta våra minnen och visa dem i tabellen Material.

Då skapade vi tabellen med hjälp av ng generate @angular/material:material-table --name=view-memories', we automatically got a file view-memories/view-memories-datasource.ts`. Den här filen innehåller falska data, så vi måste ändra den för att börja hämta från Firebase.

I view-memories-datasource.ts tar vi bort EXAMPLE_DATA och sätter en tom array:

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

Och i getSortedData uppdaterar vi fältnamnen:

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

I view-memories.component.html uppdaterar vi kolumnnamnen till date och text från vår minnesmodell. Observera att eftersom vi sparade datumet i millisekundsformat använder vi här ett datumrör för att omvandla värdet för visning i ett mer människovänligt datumformat. Slutligen tar vi bort ="dataSource.data.length" från paginatorn, eftersom vi kommer att läsa in data asynkront från 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>

Ändra view-memories.component.css till view-memories.component.scss och ställ in tabellstilen:

table{ width: 100%;}

I view-memories.component.ts ändrar vi styleUrls så att det återspeglar ovanstående namnändring till ./view-memories.component.scss. Vi uppdaterar också arrayen displayedColumns till och ställer in tabellens datakälla för att hämta data från Firebase.

Vad som händer här är att vi prenumererar på minneslistan och när vi får data instansierar vi ViewMemoriesDataSource och ställer in dess dataegenskap med data från 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 returnerar en Observable-array i ReactiveX-stil.

Notera att vi kastar this.db.list<ViewMemoriesItem>('memories')-de värden som hämtas från 'memories'-stigen-till ViewMemoriesItem. Detta tas om hand av angularfire2-biblioteket.

Vi inkluderade också unsubscribe-anropet i onDestroy-haken i Angular-komponentens livscykel.

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

Deployerar till Firebase Hosting

Nu, för att göra vår app live, ska vi distribuera den till Firebase Hosting. För det installerar vi Firebase CLI, vilket gör kommandot firebase tillgängligt:

npm install -g firebase-tools

Nu kan vi använda Firebase CLI för att logga in:

firebase login

Detta kommer att uppmana dig att välja ditt Google-konto.

Nästan ska vi initiera projektet och konfigurera Firebase Hosting:

firebase init

Vi väljer bara Hosting-alternativet.

Nästan, när vi ombeds ange sökvägen, ställer vi in den på dist/my-memories. När vi tillfrågas om vi vill konfigurera den som en app med en enda sida (dvs. skriva om alla webbadresser till /index.html) svarar vi ”ja”.

Slutligt kommer vi att stöta på: ”Filen dist/my-memories/index.html finns redan. Skriv över?” Här svarar vi ”nej.”

Detta kommer att skapa Firebase-konfigurationsfilerna .firebaserc och firebase.json med den tillhandahållna konfigurationen.

Det sista steget är att köra:

ng build --prodfirebase deploy

Och med det har vi publicerat appen till Firebase, vilket ger oss en URL som vi kan navigera till, som https://my-memories-b4c52.firebaseapp.com/view-memories, där du kan se min egen publicerade demo.

Wow, du har gått igenom handledningen! Jag hoppas att du gillade den. Du kan också titta på den fullständiga koden för den på GitHub.

Ett steg i taget

Angular är ett mycket kraftfullt ramverk för att bygga webbappar. Det har funnits länge och har visat sig fungera både för små, enkla appar och stora, komplexa appar – Angular 6 är inget undantag här.

I framtiden planerar Angular att fortsätta att förbättra och följa nya webbparadigm, till exempel webbkomponenter (Angular Elements). Om du är intresserad av att bygga hybridappar kan du kolla in Ionic, som använder Angular som underliggande ramverk.

Denna handledning täckte mycket grundläggande steg för att börja använda Angular, Material och Firebase. Men du bör ta hänsyn till att du för verkliga applikationer behöver lägga till validering, och för att göra din applikation lättare att underhålla och skala vill du förmodligen följa bästa praxis som att använda tjänster, återanvändbara komponenter osv. Det får bli ämnet för en annan artikel – förhoppningsvis räckte den här artikeln för att väcka din aptit på Angular-utveckling!

Relaterat: Alla förmåner, inget krångel: En handledning om Angular 9

Leave a Reply