Учебник по 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 .

Приложение Angular 6 сразу после скаффолдинга

Что происходит за кулисами, так это то, что CLI транспилирует все .ts (файлы TypeScript) в vanilla JS, собирает все необходимые зависимости из папки пакетов node_modules и выводит результат в виде набора файлов, которые обслуживаются через локальный веб-сервер. который работает на порту 4200.

Файлы проекта

Если вы не знакомы со структурой папок проекта Angular, самое важное, что вам нужно знать, это то, что весь код, связанный с приложением, находится внутри папки src . Обычно вы создаете все свои модули и директивы в этой папке в соответствии с архитектурой вашего приложения (например, пользователь, корзина, продукт).

Структура папок проекта Angular 6

Начальная настройка

Итак, у нас есть начальная настройка нашего приложения. Давайте начнем вносить некоторые изменения.

Прежде чем мы начнем, давайте немного покопаемся в папке 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" } ] }, // ...

И в projectsmy-memoriesarchitectserveconfigurations :

 "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 уже включена индиго-розовая тема.

Указание вашего выбора готовой темы Angular 6

Вам нужно будет перезапустить ng serve , чтобы выбрать тему, или вы можете выбрать другую готовую тему.

Связанный: Создавайте ультрасовременные веб-приложения с помощью Angular Material

Базовая компоновка

Чтобы получить первоначальный макет sidenav, мы будем использовать схемы, поставляемые с материалом. Но это нормально, если вы хотите использовать другой макет.

(Короче говоря, схемы позволяют применять преобразования к проекту: вы можете создавать, изменять или удалять файлы по мере необходимости. В этом случае он формирует макет sidenav для нашего приложения.)

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

Это создаст компонент sidenav с минимальной настройкой, готовый к запуску. Разве это не здорово?

Он также включил все необходимые модули в наш app.module.ts .

Недавно созданный компонент Angular 6 «my-nav».

Поскольку мы используем 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.

Во-вторых, мы установим пакеты firebase и angularfire2 :

 npm install firebase angularfire2 --save

И затем в каждом из этих трех файлов:

  1. /src/environments/environment.ts
  2. /src/environments/environment.hmr.ts
  3. /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') }) } 

Разрешение доступа на чтение и запись к вашей базе данных Firebase.

Вам нужно будет разрешить публичный доступ к правилам базы данных, чтобы анонимные пользователи могли читать и писать в нее. Обратите внимание , что с этой настройкой любой пользователь сможет читать/изменять/удалять данные вашего приложения. Убедитесь, что вы настроили свои правила соответствующим образом, прежде чем переходить к производству.

Кроме того, чтобы принять изменения среды, вам необходимо перезапустить процесс ng serve .

Теперь, когда мы вернемся в браузер и нажмем кнопку сохранения, мы увидим, что память была добавлена ​​в базу данных:

Наша тестовая память добавлена ​​в базу данных Firebase нашего дневникового приложения.

Давайте посмотрим, как мы можем получить наши воспоминания и отобразить их в таблице материалов.

Когда мы создали таблицу с помощью 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(); } }
Связанный: Создание многоплатформенных мобильных приложений в реальном времени: примеры с использованием Ionic Framework и Firebase

Развертывание на хостинге 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!

Связанный: Все льготы, никаких хлопот: учебник по Angular 9