本文概述
- Angular 6:基础知识
- Angular 6:新功能
- Angular 6 CLI
- 创建一个Angular 6项目
- 初始设置
- 添加Material Angular 6 UI库
- 基本布局
- 生成应用(回忆日记)
- Angular 6教程:与Firebase连接
- 部署到Firebase托管
- 一步一步来
Angular 6出来了!最杰出的变化在于其CLI和注入服务的方式。如果你想编写本教程中的第一个Angular 6应用程序(或Angular / Firebase应用程序), 我们将介绍初始设置的基本步骤并创建一个小型日记应用程序。
Angular 6:基础知识
如果你以前从未使用过Angular, 请允许我简要介绍一下它及其工作原理。
Angular是一个JavaScript框架, 旨在支持为台式机和移动设备构建单页应用程序(SPA)。
该框架包括一整套指令和模块, 使你可以轻松实现Web应用程序的一些最常见方案, 例如导航, 授权, 表单和报告。它还带有所有必需的软件包, 以使用Jasmine框架添加测试并使用Karma或Protractor测试运行程序运行它们。
Angular体系结构基于组件, 模板, 指令和服务。它为你的服务提供了内置的依赖项注入机制, 以及双向数据绑定以将视图与组件代码连接起来。
Angular使用TypeScript, 它是JS的类型化超集, 它将使某些事情变得更容易, 尤其是如果你来自类型化语言背景。
Angular 6:新功能
Angular 6中的新功能的简要摘要:
- 同步框架包(@ angular / core, @ angular / common, @ angular / compiler等), CLI, Material和CDK的主要版本号的策略。这将有助于使跨兼容性变得更加清晰:你可以快速浏览一下版本号, 以了解密钥包是否相互兼容。
- 新的CLI命令:
- ng update可以聪明地升级软件包版本, 更新依赖版本并保持同步。 (例如, 当运行ng update @ angular / core时, 所有框架以及RxJS都会被更新。)如果软件包中包含原理图, 它也会运行原理图。 (如果较新的版本包含需要更改代码的重大更改, 则原理图将为你更新代码。)
- ng add添加新软件包(并运行脚本, 如果适用)
- 服务现在引用将提供服务的模块, 而不是像以前那样引用服务的模块。
作为最后一次更改的含义的示例, 你的代码通常如下所示:
@NgModule({
// ...
providers: [MyService]
})
…随着Angular 6的这一特殊更改, 它看起来像:
@Injectabe({
providedIn: 'root', })
这些称为树可摇动的提供程序, 它们允许编译器删除未引用的服务, 从而使束更小。
Angular 6 CLI
ng命令行界面是Angular的非常重要的一部分, 可让你在编写应用程序时更快地移动。
使用CLI, 你可以非常轻松地构建初始应用程序, 生成新的组件, 指令等, 并在本地环境中构建和运行你的应用程序。
创建一个Angular 6项目
好, 足够多的谈话。让我们弄脏双手, 开始编码。
首先, 你需要在计算机上安装Node.js和npm。
现在, 让我们继续安装CLI:
npm install -g @angular/cli
由于-g开关, 这将全局安装ng CLI命令。
一旦有了这些, 就可以使用ng new为我们的应用程序获取初始支架:
ng new my-memories --style=scss
这将创建一个my-memories文件夹, 创建所有必需的文件以使你的初始设置准备就绪, 并安装所有必需的软件包。 –style = scss开关是可选的, 它将设置编译器以将SCSS文件编译为CSS, 稍后我们将需要它。
安装完成后, 你可以CD my-memories并运行ng serve。这将启动构建过程, 并在http:// localhost:4200上为你的应用程序提供服务的本地Web服务器。
幕后发生的事情是CLI将所有.ts(TypeScript文件)转换为原始JS, 从packages文件夹node_modules收集了所有必需的依赖项, 并将结果输出到一组文件中, 这些文件通过本地Web服务器提供服务在端口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将渲染class title属性的值, 并在更改时随时对其进行更新。
<!--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>
让我们继续, 将班级标题更新为”我的回忆!”。
...
export class AppComponent {
title = 'My Memories!';
}
...
我们将看到编译器正在进行更改, 浏览器将刷新以显示更新后的标题。
这意味着Angular 6的ng服务监视我们的文件更改, 并在每次将更改引入任何文件时进行渲染。
为了使编码更加友好并避免每次进行更改时都刷新整个页面, 我们可以利用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": {
"hmr": {
"browserTarget": "my-memories:build:hmr"
}, // ...
现在, 通过在compilerOptions下添加以下内容来更新tsconfig.app.json以包括必要的类型(好吧, 类型):
"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标志是否为true。如果是这样, 我们从hmr.ts中调用先前定义的函数, 该函数启用了热模块替换;否则, 我们会像往常一样引导它。
现在, 当我们运行ng serve –hmr –configuration = hmr时, 我们将调用hmr配置, 并且当我们对文件进行更改时, 我们将获得更新而无需完全刷新。第一个–hmr用于webpack, 而–configuration = hmr用于Angular使用hmr环境。
渐进式Web应用程序(PWA)
为了添加Angular 6 PWA支持并启用应用程序的离线加载, 我们可以使用新的CLI命令之一ng add:
ng add @angular/[email protected]
请注意, 我正在添加版本, 因为在撰写本教程时, 最新版本引发了错误。 (你可以尝试不使用它, 只需使用ng add @ angular / pwa检查它是否对你有用。)
好的, 所以在运行命令之后, 我们将在项目中看到很多更改。最重要的更改是它添加了:
- 对angular.json资产文件中的manifest.json的引用, 使其包含在构建输出中, 以及” serviceWorker”:在生产构建中为true
- 带有初始设置的ngsw-config.json文件可缓存应用程序运行所需的所有文件
- index.html文件中的manifest.json元标记
- manifest.json文件本身, 具有应用程序的基本配置
- 服务工作者在应用程序模块ServiceWorkerModule.register(‘/ ngsw-worker.js’, {enabled:environment.production})中的加载(请注意, 服务工作者仅在生产环境中启用)
因此, 这意味着当用户首次访问URL时, 将下载文件。此后, 如果用户尝试在没有网络服务的情况下访问URL, 则该应用程序仍将通过拉取那些缓存的文件来运行。
添加Material Angular 6 UI库
到目前为止, 我们已经完成了初始设置, 并且可以开始构建应用程序了。要利用已构建的组件, 我们可以使用Angular 6版本的Material。
为了在我们的应用程序上安装材料包, 我们将再次使用ng add:
ng add @angular/material
运行完之后, 我们将看到添加了一些新软件包以及一些基本样式配置:
- index.html包括Roboto字体和Material图标
- BrowserAnimationsModule已添加到我们的AppModule中
- angular.json的靛蓝主题已经为我们包含
你需要重新启动服务才能选择主题, 也可以选择其他预建主题。
相关:使用Angular Material构建超现代的Web应用程序
基本布局
要获得初始的sidenav布局, 我们将使用Material随附的示意图。但是如果你要使用其他布局也可以。
(简而言之, 原理图使你可以将变换应用于项目:可以根据需要创建, 修改或删除文件。在这种情况下, 它为我们的应用程序提供了sidenav布局。)
ng generate @angular/material:material-nav --name=my-nav
这将创建一个sidenav组件, 并准备启动最少的设置。那不是很好吗?
它还在我们的app.module.ts中包含了所有必要的模块。
由于使用的是SCSS, 因此需要将my-nav.component.css文件重命名为my-nav.component.scss, 并在my-nav.component.ts中更新相应的引用styleUrls以使用新名称。
现在要使用新组件, 让我们转到app.component.html并删除所有初始代码, 只剩下:
<app-my-nav></app-my-nav>
当我们返回浏览器时, 将看到以下内容:
让我们更新链接, 使其只有我们想要的两个选项。
首先, 让我们创建两个新组件:
ng g c 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设置为父级, 并将我们创建的两个组件设置为子级。这是因为我们在MyNavComponent中包含了<router-outlet>, 并且每当打到两条路径之一时, 我们将渲染放置<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>
在这里, 我们使用席卡, 并添加两个字段:日期和文本区域。
请注意, 我们正在使用[(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);
}
}
在这里, 我们正在初始化通过ngModel绑定的memory属性。实例化AddMemoryComponent组件后, 内存将为空对象。然后, 当ngModel指令运行时, 它将能够将输入值分配给memory.date和memory.text。如果我们不这样做, 则会收到无法设置未定义属性”日期/文本”的错误。
同时, add-memory.component.scss需要具有:
.memory-card {
min-width: 150px;
max-width: 400px;
width: 100%;
margin: auto;
}
.mat-form-field {
width: 100%;
}
由于我们有<pre> {{内存| json}} </ pre>, 我们可以在视图中看到内存的当前状态。如果我们使用浏览器, 那么到目前为止的结果是:
在视图中, 我们通过(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添加到你的Web应用程序”来获得上述文件所需的配置详细信息。
之后, 我们将在我们的app.module.ts中包含Firebase模块:
import { AngularFireModule } from 'angularfire2';
import { AngularFireDatabaseModule } from 'angularfire2/database';
import { environment } from '../environments/environment';
// ...
Imports:[
// ...
AngularFireModule.initializeApp(environment.firebase), AngularFireDatabaseModule, // ...
]
然后在add-memory.component.ts中, 将数据库注入构造函数中, 并将表单中的值保存到数据库中。当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')
})
}
你需要允许对数据库规则进行公开访问, 以便匿名用户可以对其进行读写。请注意, 使用此设置, 任何用户都可以读取/更改/删除你的应用数据。在生产之前, 请确保相应地设置了规则。
另外, 要获取环境更改, 你将需要重新启动服务过程。
现在, 当我们返回浏览器并单击保存按钮时, 我们将看到内存已添加到数据库中:
让我们看一下如何检索我们的记忆并将其显示在Material表中。
回到使用ng generate @ angular / material:material-table –name = view-memories’创建表时, 我们自动获得了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中, 我们将使用内存模型将列的名称更新为日期和文本。请注意, 由于我们以毫秒格式保存了日期, 因此在这里我们使用日期管道将值转换为以更人性化的日期格式显示。最后, 我们从分页器中删除了[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。我们还将把displayColumns数组更新为[‘date’, ‘text’], 并设置表数据源以从Firebase获取数据。
这里发生的是我们正在订阅内存列表, 当我们收到数据时, 我们实例化ViewMemoriesDataSource并使用Firebase中的数据设置其data属性。
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返回一个ReactiveX样式的Observable数组。
请注意, 我们正在将this.db.list <ViewMemoriesItem>(‘memories’)(从” memories”路径提取的值)转换为ViewMemoriesItem。 angularfire2库会对此进行处理。
我们还将取消订阅调用包括在Angular组件生命周期的onDestroy挂钩中。
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 Hosting。为此, 我们将安装Firebase CLI, 这将使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是用于构建Web应用程序的非常强大的框架。它已经存在了很长时间, 并且已经在小型, 简单应用程序以及大型, 复杂的应用程序中证明了自己的实力— Angular 6也不例外。
展望未来, Angular计划继续改进并遵循新的Web范例, 例如Web组件(Angular Elements)。如果你对构建混合应用程序感兴趣, 可以查看Ionic, 它使用Angular作为其基础框架。
本教程涵盖了开始使用Angular, Material和Firebase的非常基本的步骤。但是你应该考虑到, 对于实际应用程序, 你需要添加验证, 并且为了使你的应用程序更易于维护和扩展, 你可能需要遵循最佳实践, 例如使用服务, 可重用组件等。 。那将是另一篇文章的主题-希望这篇文章足以激发你对Angular开发的胃口!
相关:所有特权, 没有麻烦:Angular 9教程
评论前必须登录!
注册