Учебник по Angular 6: новые функции с новой силой
Опубликовано: 2022-03-11Угловой 6 вышел! Самые выдающиеся изменения коснулись интерфейса командной строки и способа внедрения сервисов. Если вы хотите написать свое самое первое приложение Angular 6 — или приложение Angular/Firebase — в этом руководстве мы рассмотрим основные шаги начальной настройки и создадим небольшое приложение-дневник.
Угловой 6: Основы
Если вы никогда раньше не использовали Angular, позвольте мне кратко описать его и то, как он работает.
Angular — это среда JavaScript, предназначенная для поддержки создания одностраничных приложений (SPA) как для настольных компьютеров, так и для мобильных устройств.
Платформа включает в себя полный набор директив и модулей, которые позволяют легко реализовать некоторые из наиболее распространенных сценариев для веб-приложения, такие как навигация, авторизация, формы и отчетность. Он также поставляется со всеми необходимыми пакетами для добавления тестов с использованием платформы Jasmine и их запуска с помощью средств запуска тестов Karma или Protractor.
Архитектура Angular основана на компонентах, шаблонах, директивах и сервисах. Он предоставляет встроенный механизм внедрения зависимостей для ваших служб, а также двустороннюю привязку данных для соединения ваших представлений с кодом вашего компонента.
Angular использует TypeScript, типизированный надмножество JS, и упростит некоторые вещи, особенно если вы имеете опыт работы с типизированным языком.
Angular 6: новые возможности
Краткий обзор новых функций в Angular 6:
- Политика синхронизации основных номеров версий для пакетов фреймворка (
@angular/core
,@angular/common
,@angular/compiler
и т. д.), CLI, Material и CDK. Это поможет сделать кросс-совместимость более понятной в будущем: по номеру версии вы можете сказать, совместимы ли ключевые пакеты друг с другом. - Новые команды командной строки
ng
:-
ng update
для интеллектуального обновления версий пакетов, обновления версий зависимостей и их синхронизации. (Например, при запускеng update @angular/core
будут обновлены все фреймворки, а также RxJS.) Он также запустит схемы , если они включены в пакет. (Если более новая версия содержит критические изменения, требующие изменений в коде, схема обновит ваш код за вас.) -
ng add
для добавления новых пакетов (и запуска скриптов, если применимо)
-
- Службы теперь ссылаются на модули, которые будут их предоставлять, а не на модули, ссылающиеся на службы, как раньше.
В качестве примера того, что означает это последнее изменение, где ваш код выглядел так:
@NgModule({ // ... providers: [MyService] })
… с этим конкретным изменением в Angular 6 это будет выглядеть так:
@Injectabe({ providedIn: 'root', })
Такие поставщики называются древовидными провайдерами и позволяют компилятору удалять сервисы, на которые нет ссылок, что приводит к уменьшению размера пакетов.
Угловой 6 интерфейс командной строки
Интерфейс командной строки ng
является очень важной частью Angular и позволяет вам двигаться быстрее при кодировании вашего приложения.
С помощью интерфейса командной строки вы можете очень легко формировать исходную настройку приложения, создавать новые компоненты, директивы и т. д., а также создавать и запускать приложение в локальной среде.
Создание проекта Angular 6
Ладно, хватит разговоров. Давайте запачкаем руки и начнем кодировать.
Для начала вам понадобятся Node.js и npm, установленные на вашем компьютере.
Теперь давайте продолжим и установим CLI:
npm install -g @angular/cli
Это установит команду ng
CLI глобально из-за ключа -g
.
Получив это, мы можем получить исходный каркас для нашего приложения с помощью ng new
:
ng new my-memories --style=scss
Это создаст папку my-memories
, создаст все необходимые файлы, чтобы подготовить первоначальную настройку к запуску, и установит все необходимые пакеты. Переключатель --style=scss
является необязательным и настроит компилятор для компиляции файлов SCSS в CSS, который нам понадобится позже.
После завершения установки вы можете cd my-memories
и запустить ng serve
. Это запустит процесс сборки и локальный веб-сервер, который обслуживает ваше приложение по адресу http://localhost:4200
.
Что происходит за кулисами, так это то, что CLI транспилирует все .ts
(файлы TypeScript) в vanilla JS, собирает все необходимые зависимости из папки пакетов node_modules
и выводит результат в виде набора файлов, которые обслуживаются через локальный веб-сервер. который работает на порту 4200.
Файлы проекта
Если вы не знакомы со структурой папок проекта Angular, самое важное, что вам нужно знать, это то, что весь код, связанный с приложением, находится внутри папки src
. Обычно вы создаете все свои модули и директивы в этой папке в соответствии с архитектурой вашего приложения (например, пользователь, корзина, продукт).
Начальная настройка
Итак, у нас есть начальная настройка нашего приложения. Давайте начнем вносить некоторые изменения.
Прежде чем мы начнем, давайте немного покопаемся в папке src
. Начальная страница 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>
Здесь мы видим базовый HTML и <app-root>
. Это компонент Angular, и Angular 6 вставляет код нашего компонента.
Мы найдем файл app/app.component.ts
, в котором селектор app-root
соответствует тому, что находится в файле index.html
.
Компонент представляет собой оформленный класс TypeScript и в данном случае содержит свойство title
. Декоратор @Component
указывает Angular включить поведение компонента в класс. В дополнение к селектору он указывает, какой HTML-файл отображать и какие таблицы стилей использовать.
import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent { title = 'app'; }
Если мы посмотрим на app.component.html
, то увидим интерполяционную привязку {{title}}
. Здесь происходит вся волшебная привязка, и Angular отображает значение свойства title класса и обновляет его каждый раз, когда оно изменяется.
<!--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>
Давайте продолжим и изменим title
класса на 'My Memories!'
.
... export class AppComponent { title = 'My Memories!'; } ...
Мы увидим, как компилятор обработает наше изменение, а браузер обновится, чтобы отобразить наш обновленный заголовок.
Это означает, что ng serve
в Angular 6 следит за изменениями в наших файлах и отображает их каждый раз, когда в какой-либо файл вносятся изменения.
Чтобы сделать программирование более дружественным и избежать полного обновления страницы каждый раз, когда мы вносим изменения, мы можем воспользоваться преимуществом горячей замены модулей webpack (HMR), которая просто обновляет фрагмент JS/CSS, который был изменен, вместо того, чтобы производить полное обновление до показать свои изменения.
Настройка HMR
Во-первых, нам нужно настроить среду.
Создайте файл src/environments/environment.hmr.ts
со следующим содержимым:
export const environment = { production: false, hmr: true };
Обновите src/environments/environment.prod.ts
и добавьте флаг hmr: false
в среду:
export const environment = { production: true, hmr: false };
Затем обновите src/environments/environment.ts
и добавьте флаг hmr: false
в среду:
export const environment = { production: false, hmr: false };
Затем в файле angular.json
обновите эту часть:
"projects": { "my-memories": { // ... "architect": { "build": { // ... "configurations": { "hmr":{ "fileReplacements":[ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.hmr.ts" } ] }, // ...
И в projects
→ my-memories
→ architect
→ serve
→ configurations
:
"projects": { "my-memories": { "architect": { // ... "serve": { // ... "configurations": { "hmr": { "browserTarget": "my-memories:build:hmr" }, // ...
Теперь обновите tsconfig.app.json
, включив в него необходимые types
(ну, тип), добавив это compilerOptions
:
"compilerOptions": { // ... "types": [ "node" ]
Далее мы установим модуль @angularclass/hmr
в качестве зависимости разработки:
npm install --save-dev @angularclass/hmr
Затем настройте его, создав файл 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(); }); };
Затем обновите src/main.ts
, чтобы использовать вышеуказанную функцию:
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)); }
Что мы здесь делаем, так это заставляем bootstrap вызывать анонимную функцию, а затем спрашиваем, истинен ли флаг environment.hmr
. Если это так, мы вызываем ранее определенную функцию из hmr.ts
, которая включила горячую замену модуля; в противном случае мы загружаем его, как раньше.
Теперь, когда мы запускаем ng serve --hmr --configuration=hmr
, мы будем вызывать конфигурацию hmr
, и когда мы будем вносить изменения в файлы, мы будем получать обновления без полного обновления. Первый --hmr
для веб-пакета, а --configuration=hmr
для Angular для использования среды hmr
.
Прогрессивное веб-приложение (PWA)
Чтобы добавить поддержку Angular 6 PWA и включить автономную загрузку приложения, мы можем использовать одну из новых команд CLI, ng add
:
ng add @angular/[email protected]
Обратите внимание, что я добавляю версию, так как последняя версия, когда я писал это руководство, выдавала ошибку. (Вы можете попробовать без него и проверить, работает ли он для вас, просто используя ng add @angular/pwa
.)
Итак, после того, как мы запустим команду, мы увидим много изменений в нашем проекте. Наиболее важные изменения заключаются в том, что он добавил:
- Ссылка на
manifest.json
в файле ресурсовangular.json
, чтобы он был включен в выходные данные сборки, а также"serviceWorker": true
в производственных сборках. -
ngsw-config.json
с начальной настройкой для кэширования всех файлов, необходимых для запуска приложения. - Метатег
manifest.json
в файлеindex.html
- Сам файл
manifest.json
с базовой конфигурацией приложения. - Сервисный работник загружается в модуль приложения
ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production })
(обратите внимание, что сервисный работник будет включен только в производственных средах)
Итак, теперь это означает, что когда пользователь впервые обращается к URL-адресу, файлы будут загружены. После этого, если пользователь попытается получить доступ к URL-адресу без сетевой службы, приложение по-прежнему будет работать, извлекая эти кэшированные файлы.
Добавление библиотеки пользовательского интерфейса Material Angular 6
На данный момент у нас есть первоначальная настройка, и мы готовы приступить к созданию нашего приложения. Чтобы использовать уже созданные компоненты, мы можем использовать версию Material для Angular 6.
Чтобы установить пакет material
в наше приложение, мы снова воспользуемся ng add
:
ng add @angular/material
После того, как мы запустим это, мы увидим несколько добавленных новых пакетов и некоторую базовую конфигурацию стиля:
-
index.html
включает шрифт Roboto и значки материалов. -
BrowserAnimationsModule
добавлен в нашAppModule
-
angular.json
уже включена индиго-розовая тема.
Вам нужно будет перезапустить ng serve
, чтобы выбрать тему, или вы можете выбрать другую готовую тему.
Базовая компоновка
Чтобы получить первоначальный макет sidenav, мы будем использовать схемы, поставляемые с материалом. Но это нормально, если вы хотите использовать другой макет.
(Короче говоря, схемы позволяют применять преобразования к проекту: вы можете создавать, изменять или удалять файлы по мере необходимости. В этом случае он формирует макет sidenav для нашего приложения.)
ng generate @angular/material:material-nav --name=my-nav
Это создаст компонент sidenav с минимальной настройкой, готовый к запуску. Разве это не здорово?
Он также включил все необходимые модули в наш app.module.ts
.
Поскольку мы используем SCSS, нам нужно переименовать файл my- my-nav.component.css
в my-nav.component.scss
, а в my-nav.component.ts
обновить соответствующую ссылку styleUrls
, чтобы использовать новое имя.
Теперь, чтобы использовать новый компонент, давайте перейдем к app.component.html
и удалим весь исходный код, оставив только:
<app-my-nav></app-my-nav>
Когда мы вернемся в браузер, вот что мы увидим:
Давайте обновим ссылки, чтобы иметь только два нужных параметра.
Во-первых, давайте создадим два новых компонента:
ng gc AddMemory ng generate @angular/material:material-table --name=view-memories
(Второй — схема Материала, используемая для создания таблицы.)
Затем в my-nav
мы обновим настройки ссылок и включим <router-outlet>
для отображения наших компонентов контента:
<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>
Кроме того, в app.component.html
нам нужно обновить его, чтобы он содержал только основной <router-outlet>
(т. е. удалить <my-nav>
):

<router-outlet></router-outlet>
Далее в AppModule
мы включим маршруты:
import { RouterModule, Routes } from '@angular/router'; // ... imports: [ // ... RouterModule.forRoot([ { path: '', component: MyNavComponent, children: [ { path: 'add-memory', component: AddMemoryComponent }, { path: 'view-memories', component: ViewMemoriesComponent } ] }, ]), ]
Обратите внимание, что мы устанавливаем MyNavComponent
в качестве родителя, а два созданных нами компонента — в качестве дочерних. Это связано с тем, что мы включили <router-outlet>
в MyNavComponent
, и всякий раз, когда мы сталкиваемся с одним из этих двух маршрутов, мы будем отображать дочерний компонент, где был размещен <router-outlet>
.
После этого, когда мы обслуживаем приложение, мы должны увидеть:
Создайте приложение (дневник воспоминаний)
Хорошо, теперь давайте создадим форму для сохранения новых воспоминаний в наш дневник.
Нам нужно импортировать некоторые модули материалов и модуль форм в наш app.module.ts
:
import { FormsModule } from '@angular/forms'; import { MatCardModule, MatFormFieldModule, MatInputModule, MatDatepickerModule, MatNativeDateModule } from '@angular/material'; // ... Imports:[ // ... MatCardModule, MatFormFieldModule, MatInputModule, MatDatepickerModule, FormsModule, MatNativeDateModule, // ... ]
А затем в add-memory.component.html
мы добавим форму:
<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>
Здесь мы используем mat-card
и добавляем два поля, date
и textarea
.
Обратите внимание, что мы используем [(ngModel)]
. Эта директива Angular свяжет выражение memory.date
и свойство memory
в классе друг с другом, как мы увидим позже. ( [(ngModel)]
— это синтаксический сахар — ярлык для двусторонней привязки данных из класса к представлению и из представления к классу. Это означает, что когда вы вводите текст в представление, memory.date
будет отражать эти изменения. в экземпляре класса, и если вы внесете изменения в memory.date
в экземпляре класса, представление будет отражать изменения.)
В add-memory.component.ts
код будет выглядеть так:
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); } }
Здесь мы инициализируем свойство memory
, привязанное через ngModel
. При создании экземпляра компонента AddMemoryComponent
memory
будет пустым объектом. Затем, когда директива ngModel
запустится, она сможет присвоить входное значение memory.date
и memory.text
. Если бы мы этого не сделали, то получили бы ошибку Cannot set property 'date/text' of undefined
.
Между тем, add-memory.component.scss
должен иметь:
.memory-card { min-width: 150px; max-width: 400px; width: 100%; margin: auto; } .mat-form-field { width: 100%; }
Поскольку у нас есть <pre> {{ memory | json }} </pre>
<pre> {{ memory | json }} </pre>
мы можем видеть текущее состояние memory
в представлении. Если мы перейдем к браузеру, вот результат:
В представлении мы привязали форму через (ngSubmit)="onSubmit()"
к функции onSubmit
в классе.
onSubmit() { console.log(this.memory); }
Поэтому, когда вы нажимаете кнопку «Спасите меня!» кнопку, вы получите внутреннее представление пользовательского ввода, отправленного в журнал консоли:
Учебник по Angular 6: подключение к Firebase
Далее мы подключим наш проект к Firebase, чтобы сохранить наши воспоминания.
Сначала мы перейдем в консоль Firebase и создадим там проект.
Во-вторых, мы установим пакеты firebase
и angularfire2
:
npm install firebase angularfire2 --save
И затем в каждом из этих трех файлов:
-
/src/environments/environment.ts
-
/src/environments/environment.hmr.ts
-
/src/environments/environment.prod.ts
… мы добавим нашу конфигурацию 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>' } };
Вы можете получить необходимые сведения о конфигурации для вышеуказанных файлов, нажав «Добавить Firebase в ваше веб-приложение» на странице обзора проекта.
После этого мы включим модули Firebase в наш app.module.ts
:
import { AngularFireModule } from 'angularfire2'; import { AngularFireDatabaseModule } from 'angularfire2/database'; import { environment } from '../environments/environment'; // ... Imports:[ // ... AngularFireModule.initializeApp(environment.firebase), AngularFireDatabaseModule, // ... ]
А в add-memory.component.ts
базу в конструкторе и сохраняем значения из формы в базу. Когда push-обещание от Firebase успешно, мы регистрируем успех в консоли и сбрасываем модель:
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') }) }
Вам нужно будет разрешить публичный доступ к правилам базы данных, чтобы анонимные пользователи могли читать и писать в нее. Обратите внимание , что с этой настройкой любой пользователь сможет читать/изменять/удалять данные вашего приложения. Убедитесь, что вы настроили свои правила соответствующим образом, прежде чем переходить к производству.
Кроме того, чтобы принять изменения среды, вам необходимо перезапустить процесс ng serve
.
Теперь, когда мы вернемся в браузер и нажмем кнопку сохранения, мы увидим, что память была добавлена в базу данных:
Давайте посмотрим, как мы можем получить наши воспоминания и отобразить их в таблице материалов.
Когда мы создали таблицу с помощью ng generate @angular/material:material-table --name=view-memories', we automatically got a file
view-memories/view-memories-datasource.ts`. Этот файл содержит поддельные данные, поэтому нам нужно изменить его, чтобы начать извлечение из Firebase.
В view-memories-datasource.ts
мы удалим EXAMPLE_DATA
и установим пустой массив:
export class ViewMemoriesDataSource extends DataSource<ViewMemoriesItem> { data: ViewMemoriesItem[] = []; // ...
И в getSortedData
обновим имена полей:
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; } }); }
В view-memories.component.html
мы обновим имена столбцов до date
и text
из нашей модели памяти. Обратите внимание, что, поскольку мы сохранили дату в миллисекундном формате, здесь мы используем канал даты для преобразования отображаемого значения в более удобный для человека формат даты. Наконец, мы удаляем [length]="dataSource.data.length"
из пагинатора, так как мы будем асинхронно загружать данные из 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>
Измените view-memories.component.css
на view-memories.component.scss
и установите стиль таблицы:
table{ width: 100%; }
В view-memories.component.ts
мы изменим styleUrls
, чтобы отразить указанное выше переименование на ./view-memories.component.scss
. Мы также изменим массив displayedColumns
на ['date', 'text']
и настроим источник данных таблицы для получения данных из Firebase.
Здесь происходит то, что мы подписываемся на список воспоминаний, и когда мы получаем данные, мы создаем экземпляр ViewMemoriesDataSource
и устанавливаем его свойство данных с данными из 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 возвращает массив Observable в стиле ReactiveX.
Обратите внимание, что мы this.db.list<ViewMemoriesItem>('memories')
— значения, извлеченные из пути 'memories'
— к ViewMemoriesItem
. Об этом позаботится библиотека angularfire2
.
Мы также включили вызов отмены unsubscribe
в хук onDestroy
жизненного цикла компонента 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(); } }
Развертывание на хостинге Firebase
Теперь, чтобы запустить наше приложение, давайте развернем его на хостинге Firebase. Для этого мы установим интерфейс командной строки Firebase, который сделает доступной команду firebase
:
npm install -g firebase-tools
Теперь мы можем использовать Firebase CLI для входа в систему:
firebase login
Вам будет предложено выбрать свою учетную запись Google.
Далее мы инициализируем проект и настроим Firebase Hosting:
firebase init
Мы просто выберем опцию Хостинг.
Далее, когда нас спросят о пути, мы установим его на dist/my-memories
. Когда нас спросят, следует ли настроить его как одностраничное приложение (т. е. переписать все URL-адреса на /index.html
), мы ответим «да».
Наконец, мы нажимаем: «Файл dist/my-memories/index.html уже существует. Переписать?» Здесь мы скажем «нет».
Это создаст файлы конфигурации Firebase .firebaserc
и firebase.json
с предоставленной конфигурацией.
Последний шаг — запустить:
ng build --prod firebase deploy
И с этим мы опубликуем приложение в Firebase, который предоставляет нам URL-адрес для перехода, например https://my-memories-b4c52.firebaseapp.com/view-memories, где вы можете просмотреть мои собственные опубликованные демо.
Вау, вы прошли обучение! Я надеюсь, что вам понравилось. Вы также можете проверить полный код на GitHub.
Один шаг за раз
Angular — очень мощный фреймворк для создания веб-приложений. Он существует уже давно и хорошо зарекомендовал себя как для небольших простых приложений, так и для больших и сложных — Angular 6 здесь не исключение.
В дальнейшем Angular планирует продолжать совершенствоваться и следовать новым веб-парадигмам, таким как веб-компоненты (Angular Elements). Если вы заинтересованы в создании гибридных приложений, вы можете попробовать Ionic, который использует Angular в качестве базовой платформы.
В этом руководстве были рассмотрены самые основные шаги, чтобы начать использовать Angular, Material и Firebase. Но вы должны принять во внимание, что для реальных приложений вам нужно будет добавить проверку, а чтобы упростить обслуживание и масштабирование вашего приложения, вы, вероятно, захотите следовать передовым методам, таким как использование служб, повторно используемые компоненты и т. д. Это должно быть предметом другой статьи — надеюсь, этой было достаточно, чтобы пробудить ваш аппетит к разработке Angular!