Samouczek Angular 6: Nowe funkcje z nową mocą

Opublikowany: 2022-03-11

Angular 6 wyszedł! Najbardziej wyróżniające się zmiany dotyczą interfejsu CLI i sposobu wstrzykiwania usług. Jeśli chcesz napisać swoją pierwszą aplikację Angular 6 — lub aplikację Angular/Firebase — w tym samouczku omówimy podstawowe kroki wstępnej konfiguracji i utworzymy małą aplikację do pamiętnika.

Angular 6: Podstawy

Jeśli nigdy wcześniej nie używałeś Angulara, pozwól, że przedstawię ci krótki opis tego i jak to działa.

Angular to framework JavaScript zaprojektowany do obsługi tworzenia aplikacji jednostronicowych (SPA) zarówno na komputery stacjonarne, jak i urządzenia mobilne.

Struktura zawiera pełny zestaw dyrektyw i modułów, które umożliwiają łatwe zaimplementowanie niektórych z najczęstszych scenariuszy dla aplikacji sieci Web, takich jak nawigacja, autoryzacja, formularze i raportowanie. Zawiera również wszystkie niezbędne pakiety do dodawania testów za pomocą frameworka Jasmine i uruchamiania ich za pomocą programów uruchamiających testy Karma lub Protractor.

Architektura Angular opiera się na komponentach, szablonach, dyrektywach i usługach. Zapewnia wbudowany mechanizm wstrzykiwania zależności dla twoich usług, a także dwukierunkowe wiązanie danych w celu połączenia widoków z kodem komponentu.

Angular używa TypeScript, typowanego nadzbioru JS, i ułatwi niektóre rzeczy, zwłaszcza jeśli pochodzisz z typowego języka.

Angular 6: Nowe funkcje

Krótkie podsumowanie nowych funkcji w Angular 6:

  • Zasady synchronizowania głównych numerów wersji dla pakietów frameworka ( @angular/core , @angular/common , @angular/compiler , itp.), CLI, Material i CDK. Pomoże to w zwiększeniu zgodności wzajemnej zgodności: wystarczy rzut oka na numer wersji, czy pakiety kluczy są ze sobą kompatybilne.
  • Nowe ng CLI:
    • ng update w celu inteligentnego uaktualniania wersji pakietów, aktualizowania wersji zależności i utrzymywania ich synchronizacji. (Np. podczas uruchamiania ng update @angular/core wszystkie frameworki zostaną zaktualizowane, podobnie jak RxJS.) Uruchomi również schematy , jeśli pakiet je zawiera. (Jeśli nowsza wersja zawiera istotne zmiany, które wymagają zmian w kodzie, schemat zaktualizuje Twój kod za Ciebie.)
    • ng add , aby dodać nowe pakiety (i uruchomić skrypty, jeśli dotyczy)
  • Usługi odwołują się teraz do modułów, które je dostarczą, zamiast modułów odwołujących się do usług, tak jak kiedyś.

Jako przykład tego, co oznacza ta ostatnia zmiana, gdzie kiedyś wyglądał Twój kod:

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

…z tą konkretną zmianą w Angular 6 będzie to wyglądać tak:

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

Są to tak zwane dostawcy z możliwością wstrząsania drzewami, które umożliwiają kompilatorowi usuwanie usług, do których nie ma odwołań, co skutkuje mniejszymi rozmiarami pakietów.

Kątowy 6 CLI

Interfejs wiersza poleceń ng jest bardzo ważnym elementem Angulara i umożliwia szybsze poruszanie się podczas kodowania aplikacji.

Dzięki CLI możesz bardzo łatwo stworzyć szkielet początkowej konfiguracji aplikacji, wygenerować nowe komponenty, dyrektywy itp. oraz zbudować i uruchomić aplikację w swoim lokalnym środowisku.

Tworzenie projektu Angular 6

Dobra, dość gadania. Ubrudźmy sobie ręce i zacznijmy kodować.

Aby rozpocząć, potrzebujesz Node.js i npm zainstalowanych na swoim komputerze.

Teraz przejdźmy dalej i zainstalujmy CLI:

 npm install -g @angular/cli

Spowoduje to globalną instalację polecenia ng CLI dzięki przełącznikowi -g .

Gdy już to mamy, możemy uzyskać początkowe rusztowanie dla naszej aplikacji za pomocą ng new :

 ng new my-memories --style=scss

Spowoduje to utworzenie folderu my-memories , utworzenie wszystkich niezbędnych plików, aby przygotować początkową konfigurację do uruchomienia i zainstalowanie wszystkich niezbędnych pakietów. Przełącznik --style=scss jest opcjonalny i skonfiguruje kompilator do kompilacji plików SCSS do CSS, czego będziemy potrzebować później.

Po zakończeniu instalacji możesz cd my-memories i uruchomić ng serve . Spowoduje to rozpoczęcie procesu kompilacji i lokalnego serwera internetowego, który obsługuje Twoją aplikację pod http://localhost:4200 .

Aplikacja Angular 6 zaraz po rusztowaniu

To, co dzieje się za kulisami, polega na tym, że CLI transpiluje wszystkie pliki .ts (pliki TypeScript) do waniliowego JS, zbiera wszystkie wymagane zależności z folderu pakietów node_modules i wyświetla wynik w postaci zestawu plików, które są obsługiwane przez lokalny serwer sieciowy działający na porcie 4200.

Pliki projektu

Jeśli nie znasz struktury folderów projektu Angulara, najważniejszą rzeczą, którą musisz wiedzieć, jest to, że cały kod związany z aplikacją znajduje się w folderze src . Zazwyczaj będziesz tworzyć wszystkie swoje moduły i dyrektywy w tym folderze zgodnie z architekturą aplikacji (np. użytkownik, koszyk, produkt).

Struktura folderów projektu Angular 6

Początkowe ustawienia

OK, na razie mamy początkową konfigurację naszej aplikacji. Zacznijmy wprowadzać pewne zmiany.

Zanim zaczniemy, zajrzyjmy trochę do folderu src . Strona początkowa to 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>

Tutaj widzimy podstawowy kod HTML i tag <app-root> . To jest komponent Angulara, w którym Angular 6 wstawia nasz kod komponentu.

Znajdziemy plik app/app.component.ts , który ma app-root selektora odpowiadający temu, co znajduje się w pliku index.html .

Składnik jest dekorowaną klasą TypeScript i w tym przypadku zawiera właściwość title . Dekorator @Component mówi Angularowi, aby uwzględnił zachowanie komponentu w klasie. Oprócz selektora określa plik HTML do renderowania i arkusze stylów, których należy użyć.

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

Jeśli spojrzymy na app.component.html , zobaczymy powiązanie interpolacji {{title}} . Tutaj dzieje się całe magiczne wiązanie, a Angular wyrenderuje wartość właściwości tytułu klasy i zaktualizuje ją za każdym razem, gdy się zmieni.

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

Przejdźmy dalej i zaktualizujmy title z klasy na 'My Memories!' .

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

Zobaczymy, jak kompilator przetworzy naszą zmianę, a przeglądarka odświeży się, aby pokazać zaktualizowany tytuł.

Oznacza to, że Angular 6 ng serve obserwuje zmiany w naszych plikach i renderuje za każdym razem, gdy zmiana jest wprowadzana do dowolnego pliku.

Aby uczynić kodowanie bardziej przyjaznym i uniknąć pełnego odświeżania strony za każdym razem, gdy wprowadzamy zmiany, możemy skorzystać z webpack Hot Module Replacement (HMR), który po prostu aktualizuje fragment JS/CSS, który został zmieniony, zamiast generować pełne odświeżenie do pokaż swoje zmiany.

Konfiguracja HMR

Najpierw musimy stworzyć środowisko.

Utwórz plik src/environments/environment.hmr.ts o następującej zawartości:

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

Zaktualizuj src/environments/environment.prod.ts i dodaj hmr: false do środowiska:

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

Następnie zaktualizuj src/environments/environment.ts i dodaj hmr: false do środowiska tam również:

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

Następnie w pliku angular.json zaktualizuj tę część:

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

A pod projectsmy-memoriesarchitectserveconfigurations :

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

Teraz zaktualizuj tsconfig.app.json , aby uwzględnić niezbędne types (no cóż, typ), dodając to w compilerOptions :

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

Następnie zainstalujemy moduł @angularclass/hmr jako zależność programistyczną:

 npm install --save-dev @angularclass/hmr

Następnie skonfiguruj go, tworząc plik 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(); }); };

Następnie zaktualizuj src/main.ts , aby użyć powyższej funkcji:

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

Robimy tutaj, że bootstrap wywołuje funkcję anonimową, a następnie pytamy, czy flaga environment.hmr jest prawdziwa. Jeśli tak, wywołujemy wcześniej zdefiniowaną funkcję z hmr.ts , która umożliwiła wymianę modułu na gorąco; w przeciwnym razie uruchamiamy go tak, jak kiedyś.

Teraz, gdy uruchomimy ng serve --hmr --configuration=hmr , wywołamy konfigurację hmr , a gdy wprowadzimy zmiany w plikach, otrzymamy aktualizacje bez pełnego odświeżenia. Pierwsze --hmr jest dla webpacka, a --configuration=hmr dla Angulara do używania środowiska hmr .

Progresywna aplikacja internetowa (PWA)

Aby dodać obsługę Angular 6 PWA i umożliwić ładowanie offline dla aplikacji, możemy skorzystać z jednego z nowych poleceń CLI, ng add :

 ng add @angular/[email protected]

Zauważ, że dodaję wersję, ponieważ najnowsza wersja, kiedy pisałem ten samouczek, zgłaszała błąd. (Możesz spróbować bez tego i sprawdzić, czy to działa, używając po prostu ng add @angular/pwa .)

Ok, więc po uruchomieniu polecenia zobaczymy wiele zmian w naszym projekcie. Najważniejsze zmiany to dodanie:

  • Odwołanie do manifest.json w pliku zasobów angular.json , aby zostało uwzględnione w danych wyjściowych kompilacji, a także "serviceWorker": true w kompilacjach produkcyjnych
  • Plik ngsw-config.json z początkową konfiguracją buforowania wszystkich plików niezbędnych do uruchomienia aplikacji
  • Metatag manifest.json w pliku index.html
  • Sam plik manifest.json z podstawową konfiguracją aplikacji
  • Obciążenie Service Worker w module aplikacji ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production }) (zauważ, że Service Worker będzie włączony tylko w środowiskach produkcyjnych)

Oznacza to teraz, że gdy użytkownik po raz pierwszy uzyska dostęp do adresu URL, pliki zostaną pobrane. Następnie, jeśli użytkownik spróbuje uzyskać dostęp do adresu URL bez usługi sieciowej, aplikacja będzie nadal działać, pobierając pliki z pamięci podręcznej.

Dodawanie biblioteki UI Material Angular 6

Jak dotąd mamy początkową konfigurację i jesteśmy gotowi do rozpoczęcia tworzenia naszej aplikacji. Aby wykorzystać już zbudowane komponenty, możemy użyć wersji Material w Angular 6.

Aby zainstalować pakiet material w naszej aplikacji, ponownie użyjemy ng add :

 ng add @angular/material

Po uruchomieniu zobaczymy kilka nowych pakietów i podstawową konfigurację stylu:

  • index.html zawiera czcionkę Roboto i ikony materiałów
  • Moduł BrowserAnimationsModule został dodany do naszego AppModule
  • angular.json ma już dla nas dołączony motyw indygo-różowy

Wskazuje wybór gotowego motywu Angular 6

Będziesz musiał zrestartować serwer ng serve , aby pobrać motyw, lub możesz wybrać inny gotowy motyw.

Powiązane: Twórz ultranowoczesne aplikacje internetowe za pomocą materiałów Angular

Układ podstawowy

Aby uzyskać początkowy układ sidenav, użyjemy schematów dołączonych do materiału. Ale jest OK, jeśli chcesz użyć innego układu.

(W skrócie, schematy pozwalają na zastosowanie transformacji do projektu: możesz tworzyć, modyfikować lub usuwać pliki zgodnie z potrzebami. W tym przypadku tworzy to szkielet układu sidenav dla naszej aplikacji.)

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

Spowoduje to utworzenie komponentu sidenav z minimalną konfiguracją gotową do uruchomienia. Czy to nie wspaniałe?

Zawiera również wszystkie niezbędne moduły w naszym app.module.ts .

Nowo utworzony komponent „my-nav” Angular 6

Ponieważ używamy SCSS, musimy zmienić nazwę pliku my- my-nav.component.css na my-nav.component.scss , aw my-nav.component.ts zaktualizować odpowiednie odnośniki styleUrls , aby używać nowej nazwy.

Teraz, aby skorzystać z nowego komponentu, przejdźmy do app.component.html i usuń cały początkowy kod, pozostawiając tylko:

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

Gdy wrócimy do przeglądarki, oto, co zobaczymy:

Układ czteropanelowy z Menu w lewym górnym rogu, obok niego moje-wspomnienia i trzema ponumerowanymi łączami pod Menu; czwarte okienko jest puste

Zaktualizujmy linki, aby zawierały tylko dwie opcje, których potrzebujemy.

Najpierw utwórzmy dwa nowe komponenty:

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

(Drugi to schemat materiałów używany do tworzenia tabeli.)

Następnie w my-nav zaktualizujemy, aby skonfigurować łącza i dołączyć <router-outlet> do wyświetlania naszych składników treści:

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

Ponadto w app.component.html musimy go zaktualizować, aby zawierał tylko główny <router-outlet> (tj. usuń <my-nav> ):

 <router-outlet></router-outlet>

Następnie w AppModule uwzględnimy trasy:

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

Zauważ, że ustawiamy MyNavComponent jako element nadrzędny, a dwa komponenty, które utworzyliśmy jako elementy podrzędne. Dzieje się tak, ponieważ umieściliśmy <router-outlet> w MyNavComponent i za każdym razem, gdy trafimy na jedną z tych dwóch tras, wyrenderujemy komponent podrzędny, w którym został umieszczony <router-outlet> .

Po tym, gdy obsługujemy aplikację, powinniśmy zobaczyć:

Linki po lewej stronie zostały zastąpione przez Dodaj pamięć i Wyświetl moje wspomnienia, z zaznaczeniem tego ostatniego. Puste okienko zawiera teraz tabelę z numerami identyfikacyjnymi i nazwami.

Zbuduj aplikację (Pamiętnik wspomnień)

Dobra, teraz stwórzmy formularz, aby zapisać nowe wspomnienia w naszym pamiętniku.

Będziemy musieli zaimportować niektóre moduły materiałów i moduł formularzy do naszego app.module.ts :

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

A następnie w add-memory.component.html dodamy formularz:

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

Tutaj używamy mat-card i dodajemy dwa pola, date i obszar textarea .

Zauważ, że używamy [(ngModel)] . Ta dyrektywa Angular powiąże wyrażenie memory.date i właściwość memory w klasie ze sobą, jak zobaczymy później. ( [(ngModel)] jest cukrem składniowym — skrótem do dwukierunkowego wiązania danych z klasy do widoku iz widoku do klasy. Oznacza to, że kiedy wprowadzisz tekst do widoku, memory.date odzwierciedli te zmiany w instancji klasy i jeśli wprowadzisz zmiany w memory.date w instancji klasy, widok będzie odzwierciedlał zmiany.)

W add-memory.component.ts kod będzie wyglądał tak:

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

Tutaj inicjujemy właściwość memory powiązaną przez ngModel . Gdy składnik AddMemoryComponent zostanie utworzony, memory będzie pustym obiektem. Następnie, gdy zostanie uruchomiona dyrektywa ngModel , będzie mogła przypisać wartość wejściową do memory.date i memory.text . Gdybyśmy tego nie zrobili, otrzymalibyśmy błąd Cannot set property 'date/text' of undefined .

Tymczasem add-memory.component.scss musi mieć:

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

Ponieważ mamy <pre> {{ memory | json }} </pre> <pre> {{ memory | json }} </pre> możemy zobaczyć aktualny stan memory w widoku. Jeśli przejdziemy do przeglądarki, oto dotychczasowy wynik:

Prototyp aplikacji dziennika „moje-wspomnienia”, pokazujący wewnętrzną reprezentację danych wejściowych użytkownika (data i tekst).

W widoku powiązaliśmy formularz via (ngSubmit)="onSubmit()" z funkcją onSubmit w klasie.

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

Więc kiedy klikniesz „Zapisz mnie!” przycisk, otrzymasz wewnętrzną reprezentację danych wejściowych użytkownika przesłanych do dziennika konsoli:

Wewnętrzna reprezentacja danych wejściowych użytkownika w dzienniku konsoli.

Samouczek Angular 6: Łączenie z Firebase

Następnie połączymy nasz projekt z Firebase, aby ocalić nasze wspomnienia.

Najpierw przejdziemy do konsoli Firebase i utworzymy tam projekt.

Dodawanie projektu Firebase.

Po drugie, zainstalujemy pakiety firebase i angularfire2 :

 npm install firebase angularfire2 --save

A potem w każdym z tych trzech plików:

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

…dodamy naszą konfigurację 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>' } };

Możesz uzyskać wymagane szczegóły konfiguracji dla powyższych plików, klikając „Dodaj Firebase do swojej aplikacji internetowej” na stronie przeglądu projektu.

Następnie dołączymy moduły Firebase do naszego app.module.ts :

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

A w add-memory.component.ts wstrzykujemy bazę danych do konstruktora i zapisujemy wartości z formularza do bazy danych. Gdy obietnica push z Firebase się powiedzie, rejestrujemy sukces w konsoli i resetujemy model:

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

Zezwalanie na dostęp do odczytu i zapisu w bazie danych Firebase.

Musisz zezwolić na publiczny dostęp do reguł bazy danych, aby anonimowi użytkownicy mogli z niej czytać i pisać. Pamiętaj , że przy tej konfiguracji każdy użytkownik będzie mógł odczytywać/zmieniać/usuwać dane aplikacji. Upewnij się, że odpowiednio skonfigurujesz swoje reguły, zanim przejdziesz do produkcji.

Ponadto, aby odebrać zmiany w środowisku, będziesz musiał zrestartować proces ng serve .

Teraz, gdy wrócimy do przeglądarki i klikniemy przycisk zapisu, zobaczymy, że pamięć została dodana do bazy danych:

Nasza pamięć testowa została dodana do bazy danych Firebase naszej aplikacji dziennika.

Przyjrzyjmy się, jak możemy odzyskać nasze wspomnienia i wyświetlić je w tabeli Materiał.

Kiedy tworzyliśmy tabelę za pomocą ng generate @angular/material:material-table --name=view-memories', we automatically got a file view-memories/view-memories-datasource.ts`. Ten plik zawiera fałszywe dane, więc musimy go zmienić, aby zacząć pobierać z Firebase.

W pliku view-memories-datasource.ts usuniemy EXAMPLE_DATA i ustawimy pustą tablicę:

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

A w getSortedData zaktualizujemy nazwy pól:

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

W view-memories.component.html zaktualizujemy nazwy kolumn do date i text z naszego modelu pamięci. Zauważ, że ponieważ zapisaliśmy datę w formacie milisekund, tutaj używamy potoku daty do przekształcenia wartości do wyświetlenia w bardziej przyjaznym dla człowieka formacie daty. Na koniec usuwamy [length]="dataSource.data.length" z paginatora, ponieważ będziemy ładować dane z Firebase asynchronicznie:

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

Zmień view-memories.component.css na view-memories.component.scss i ustaw styl tabeli:

 table{ width: 100%; }

W view-memories.component.ts zmienimy styleUrls , aby odzwierciedlić powyższą zmianę nazwy na ./view-memories.component.scss . Zaktualizujemy również tablicę displayedColumns do wartości ['date', 'text'] i skonfigurujemy źródło danych tabeli tak, aby pobierało dane z Firebase.

To, co się tutaj dzieje, polega na tym, że subskrybujemy listę wspomnień, a kiedy otrzymujemy dane, tworzymy instancję ViewMemoriesDataSource i ustawiamy jego właściwość danych na dane z 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 zwraca tablicę obserwowalną w stylu ReactiveX.

Zauważ, że this.db.list<ViewMemoriesItem>('memories') — wartości pobierane ze ścieżki 'memories' — na ViewMemoriesItem . Zajmuje się tym biblioteka angularfire2 .

Zawarliśmy również wywołanie unsubscribe w haczyku onDestroy cyklu życia komponentu 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(); } }
Powiązane: Tworzenie wieloplatformowych aplikacji mobilnych w czasie rzeczywistym: przykłady przy użyciu Ionic Framework i Firebase

Wdrażanie w Hostingu Firebase

Teraz, aby nasza aplikacja działała, wdróżmy ją w Hostingu Firebase. W tym celu zainstalujemy Firebase CLI, który udostępni polecenie firebase :

 npm install -g firebase-tools

Teraz możemy zalogować się za pomocą Firebase CLI:

 firebase login

To poprosi Cię o wybranie swojego konta Google.

Następnie zainicjujemy projekt i skonfigurujemy Hosting Firebase:

 firebase init

Po prostu wybierzemy opcję Hosting.

Następnie, gdy zostaniemy poproszeni o podanie ścieżki, ustawimy ją na dist/my-memories . Gdy zostaniemy zapytani, czy skonfigurować go jako aplikację jednostronicową (tj. przepisać wszystkie adresy URL do /index.html ), odpowiemy „tak”.

Na koniec klikamy „File dist/my-memories/index.html już istnieje. Przepisać?" Tutaj powiemy „nie”.

Spowoduje to utworzenie plików konfiguracyjnych .firebaserc i firebase.json z podaną konfiguracją.

Ostatnim krokiem jest uruchomienie:

 ng build --prod firebase deploy

Dzięki temu opublikujemy aplikację w Firebase, która zapewnia nam adres URL, do którego możemy przejść, np. https://my-memories-b4c52.firebaseapp.com/view-memories, gdzie możesz przeglądać moje własne opublikowane próbny.


Wow, przeszedłeś przez samouczek! Mam nadzieję, że ci się podobało. Możesz również zapoznać się z pełnym kodem na GitHub.

Krok po kroku

Angular to bardzo potężny framework do tworzenia aplikacji internetowych. Jest tam od dawna i sprawdził się zarówno w małych, prostych aplikacjach, jak i dużych, złożonych – Angular 6 nie jest tutaj wyjątkiem.

W przyszłości Angular planuje nadal ulepszać i podążać za nowymi paradygmatami sieciowymi, takimi jak komponenty sieciowe (elementy Angular). Jeśli jesteś zainteresowany tworzeniem aplikacji hybrydowych, możesz wypróbować Ionic, który wykorzystuje Angular jako podstawową platformę.

W tym samouczku omówiono bardzo podstawowe kroki, aby zacząć korzystać z Angular, Material i Firebase. Należy jednak wziąć pod uwagę, że w przypadku rzeczywistych aplikacji konieczne będzie dodanie walidacji, a aby ułatwić utrzymanie i skalowanie aplikacji, prawdopodobnie zechcesz postępować zgodnie z najlepszymi praktykami, takimi jak korzystanie z usług, komponentów wielokrotnego użytku itp. To będzie musiało być tematem innego artykułu – miejmy nadzieję, że ten wystarczył, aby pobudzić apetyt na rozwój Angulara!

Powiązane: Wszystkie korzyści, bez kłopotów: samouczek Angular 9