什么是 Angular?
# 什么是 Angular?
Angular 是一个 Web 框架,能够帮助开发者构建快速、可靠的应用
由 Google 的专业团队维护
# 基础
# 组件
构建 Angular 应用的基本构建块。
大驼峰命名 组件树
定义组件
核心属性:
- 一个包含一些配置的
@Component
装饰器 (opens new window) - 控制将渲染到 DOM 中的 HTML 模板
- 定义组件在 HTML 中如何使用的 CSS 选择器 (opens new window)
- 一个包含管理状态、处理用户输入或从服务器获取数据等行为的 TypeScript 类。
// todo-list-item.component.ts
@Component({
standalone: true,
selector: 'todo-list-item',
template: `
<li>(TODO) Read Angular Essentials Guide</li>
`,
styles: `
li {
color: red;
font-weight: 300;
}
`,
})
export class TodoListItem {
/* Component behavior is defined in here */
}
包括的元数据:
standalone: true
——— 推荐的简化组件编写体验的方法styles
——— 包含任何你想应用到组件上的 CSS 样式的字符串或字符串数组
可以将html和css分离到单独的文件中
Angular 提供了两个额外的属性: templateUrl
和 styleUrl
。
// todo-list-item.component.ts
@Component({
standalone: true,
selector: 'todo-list-item',
templateUrl: './todo-list-item.component.html',
styleUrl: './todo-list-item.component.css',
})
export class TodoListItem {
/* Component behavior is defined in here */
}
使用组件
要使用组件,你需要:
- 将组件导入到文件中
- 将其添加到组件的
imports
数组中 - 在
template
中使用该组件的选择器
// TodoList 组件导入之前的 TodoListItem 组件的示例
// todo-list.component.ts
import {TodoListItem} from './todo-list-item.component.ts';
@Component({
standalone: true,
imports: [TodoListItem],
template: `
<ul>
<todo-list-item></todo-list-item>
</ul>
`,
})
export class TodoList {}
# 管理动态数据
定义组件的状态和行为来管理动态数据。
组件需要跟踪的各种属性通常被称为**「状态」**。
定义状态
要定义状态,你可以在组件内使用 类字段语法 (opens new window)
// todo-list-item.component.ts
@Component({ ... })
export class TodoListItem {
taskTitle = '';
isComplete = false;
}
更新状态
当你想更新状态时,通常通过在组件类中定义方法来实现,这些方法可以使用 this
关键字访问各种类字段。
// todo-list-item.component.ts
@Component({ ... })
export class TodoListItem {
taskTitle = '';
isComplete = false;
completeTask() {
this.isComplete = true;
}
updateTitle(newTitle: string) {
this.taskTitle = newTitle;
}
}
# 渲染动态模板
使用 Angular 的模板语法创建动态 HTML。
渲染动态属性
当你需要在模板中显示动态内容时,Angular 使用双花括号语法来区分静态和动态内容。
@Component({
selector: 'todo-list-item',
template: `
<p>Title: {{ taskTitle }}</p>
`,
})
export class TodoListItem {
taskTitle = 'Read cup of coffee';
}
这种语法声明了 HTML 内部动态数据属性之间的 插值。因此,每当数据变化时,Angular 会自动更新 DOM,以反映该属性的新值。
# 动态属性
当你需要在 HTML 元素上动态设置标准 DOM 属性的值时,该属性会用方括号包裹,以通知 Angular 声明的值应被解释为类似 JavaScript 的语句( 带有一些 Angular 增强功能 (opens new window)),而不是纯字符串。
@Component({
selector: 'sign-up-form',
template: `
<button type="submit" [disabled]="formIsInvalid">Submit</button>
`,
})
export class SignUpForm {
formIsInvalid = true;
}
动态绑定自定义的 HTML 属性(例如, aria-
, data-
等)需要用 attr.
前缀来修饰自定义的 HTML 属性
@Component({
standalone: true,
template: `
<button [attr.data-test-id]="testId">Primary CTA</button>
`,
})
export class AppBanner {
testId = 'main-cta';
}
# 条件与渲染
@if
控制块
类似于 JavaScript 的 if
语句,Angular 使用 @if
控制块有条件地隐藏和显示模板及其内容的部分
@else
控制块
// user-controls.component.ts
@Component({
standalone: true,
selector: 'user-controls',
template: `
@if (isAdmin) {
<button>Erase database</button>
} @else {
<p>You are not authorized.</p>
}
`,
})
export class UserControls {
isAdmin = true;
}
@for
控制块
类似于 JavaScript 的 for...of
循环,Angular 提供了 @for
控制块来渲染重复的元素。
track
属性
当 Angular 使用 @for
渲染元素列表时,这些条目可能会在后续更改或移动。Angular 需要通过任何重新排序跟踪每个元素,通常是将条目的某个属性作为唯一标识符或键。
<!-- ingredient-list.component.html -->
<ul>
@for (ingredient of ingredientList; track ingredient.name) {
<li>{{ ingredient.quantity }} - {{ ingredient.name }}</li>
}
</ul>
// ingredient-list.component.ts
@Component({
standalone: true,
selector: 'ingredient-list',
templateUrl: './ingredient-list.component.html',
})
export class IngredientList {
ingredientList = [
{name: 'noodles', quantity: 1},
{name: 'miso broth', quantity: 1},
{name: 'egg', quantity: 2},
];
}
# 处理用户交互
在你的应用中处理用户交互。
事件处理
- 在圆括号内添加一个带有事件名称的属性
- 指定当事件触发时你想运行的 JavaScript 语句
<button (click)="save()">Save</button>
例如,如果我们想创建一个按钮,当 click
事件触发时运行 transformText
函数,它看起来如下所示:
// text-transformer.component.ts
@Component({
standalone: true,
selector: 'text-transformer',
template: `
<p>{{ announcement }}</p>
<button (click)="transformText()">Abracadabra!</button>
`,
})
export class TextTransformer {
announcement = 'Hello again Angular!';
transformText() {
this.announcement = this.announcement.toUpperCase();
}
}
其他常见的事件监听器示例包括:
<input (keyup)="validateInput()" />
<input (keydown)="updateInput()" />
$event
如果你需要访问 事件 (opens new window) 对象,Angular 提供了一个隐式的 $event
变量,你可以将其传递给一个函数:
<button (click)="createUser($event)">Submit</button>
# 共享代码
依赖注入允许你共享代码。
当你需要在组件之间共享逻辑时,Angular 利用 依赖注入 (opens new window)的设计模式,允许你创建一个“服务”,从而允许你将代码注入组件,并从单一事实之源管理它。
什么是服务?
服务是可重用的代码片段,可以被注入
类似于定义组件,服务由以下内容组成:
- 一个 TypeScript 装饰器,通过
@Injectable
声明该类为 Angular 服务,并允许你通过providedIn
属性(通常为'root'
)定义应用程序中哪些部分可以访问该服务,从而允许服务在应用程序中的任何地方被访问。 - 一个 TypeScript 类,定义当服务被注入时将可访问的代码
import {Injectable} from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class CalculatorService {
add(x: number, y: number) {
return x + y;
}
}
如何使用服务
- 导入服务
- 声明一个类字段,服务被注入到其中。将类字段赋值为调用内置函数
inject
创建服务的结果
这是在 Receipt
组件中的可能样子:
import { Component } from '@angular/core';
import { CalculatorService } from './calculator.service';
@Component({
selector: 'app-receipt',
template: `<h1>The total is {{ totalCost }}</h1>`,
})
export class Receipt {
private calculatorService = inject(CalculatorService);
totalCost = this.calculatorService.add(50, 25);
}
在这个例子中,通过调用 Angular 函数 inject
并将服务传递给它来使用 CalculatorService
。
# 进入开发
开始来正式学一下怎么开发Angular项目
- 安装
node.js
node --version
- 安装npm
- 安装Angular
npm install -g @angular/cli
。
- 安装集成开发工具:VsCode
# 创建
创建一个新的 Angular 项目:
npx @angular/cli new project1
启动服务
ng serve
创建一个新组件
ng generate component home
你创建 HomeComponent
时,会用到这些属性:
selector
:描述了 Angular 要如何在模板中引用本组件。standalone
:描述组件是否需要一个NgModule
。imports
:描述组件的依赖关系。template
:描述组件的 HTML 标记和布局。styleUrls
:以数组形式列出组件使用的 CSS 文件的 URL。

将新组件添加到应用的布局
将新组件 HomeComponent
添加到应用的根组件 AppComponent
打开
app.component.ts
。在
app.component.ts
中使用import
来导入HomeComponent
。在
app.component.ts
中,在@Component
中,更新imports
数组属性,并添加HomeComponent
。更新
template
属性,下面代码:template: ` <main> <header class="brand-name"> <img class="brand-logo" src="/assets/logo.svg" alt="logo" aria-hidden="true" /> </header> <section class="content"> <app-home></app-home> </section> </main> `,
保存并检查保持
ng serve
运行
应用中的 Hello world应该从 HomeComponent
更改为 home works!。
为 HomeComponent
添加特性
需求:添加一个搜索过滤器和按钮
打开
home.component.ts
在
home.component.ts
中,在@Component
中,使用此代码更新template
属性。template: ` <section> <form> <input type="text" placeholder="Filter by city" /> <button class="primary" type="button">Search</button> </form> </section> `,
打开
home.component.css
并使用如下样式更新其内容注意:在浏览器中,这些内容可以放在
src/app/home/home.component.ts
中的styles
数组中。.results { display: grid; column-gap: 14px; row-gap: 14px; grid-template-columns: repeat(auto-fill, minmax(400px, 400px)); margin-top: 50px; justify-content: space-around; } input[type="text"] { border: solid 1px #ccc; padding: 10px; border-radius: 8px; margin-right: 4px; display: inline-block; width: 30%; } button { padding: 10px; border: solid 1px #ccc; background: #ccc; color: white; border-radius: 8px; } @media (min-width: 500px) and (max-width: 768px) { .results { grid-template-columns: repeat(2, 1fr); } input[type="text"] { width: 70%; } } @media (max-width: 499px) { .results { grid-template-columns: 1fr; } }
保存运行检查
需求:创建一个新组件:住房位置组件,新组件 HousingLocationComponent
添加到应用的 HomeComponent
中
运行此命令以创建一个新的
HousingLocationComponent
ng generate component housingLocation
打开home.component.ts,导入组件
import {HousingLocationComponent} from '../housing-location/housing-location.component';
通过将
HousingLocationComponent
添加到数组中,更新@Component
元数据的imports
属性更新
@Component
元数据的template
属性,包含对<app-housing-location>
标签的引用。
为组件添加样式,打开housing-location.component.css,将以下代码放进去
.listing { background: var(--accent-color); border-radius: 30px; padding-bottom: 30px; } .listing-heading { color: var(--primary-color); padding: 10px 20px 0 20px; } .listing-photo { height: 250px; width: 100%; object-fit: cover; border-radius: 30px 30px 0 0; } .listing-location { padding: 10px 20px 20px 20px; } .listing-location::before { content: url("/assets/location-pin.svg") / ""; } section.listing a { padding-left: 20px; text-decoration: none; color: var(--primary-color); } section.listing a::after { content: "\203A"; margin-left: 5px; }
# 接口
接口 (opens new window) 是应用程序的自定义数据类型。
Angular就是使用typeScript来充分发挥在强类型编程环境中工作的优势
强类型检查降低了应用程序中的一个元素向另一个元素发送错误格式数据的可能性。这样接口的话就要好好的弄以下,创建出来使TypeScript 编译器捕获得更好
创建一个新接口
运行此命令以创建新接口
ng generate interface housinglocation
打开
src/app/housinglocation.ts
文件,写下面代码export interface HousingLocation { id: number; name: string; city: string; state: string; photo: string; availableUnits: number; wifi: boolean; laundry: boolean; }
下面来在
home.component.ts
进行导入接口import {HousingLocation} from '../housinglocation';
用如下代码替换空定义
export class HomeComponent {}
,以在组件中创建新接口的单个实export class HomeComponent { readonly baseUrl = 'https://angular.dev/assets/tutorials/common'; housingLocation: HousingLocation = { id: 9999, name: 'Test Home', city: 'Test city', state: 'ST', photo: `${this.baseUrl}/example-house.jpg`, availableUnits: 99, wifi: true, laundry: false, }; }
通过将类型为
HousingLocation
的housingLocation
属性添加到HomeComponent
类中,我们可以确认数据是否与接口的描述匹配。如果数据不符合接口的描述,IDE 将有足够的信息为我们提供有用的错误提示
感觉是不是这样进度会相对比较慢一点
那就速通,下面会集中精华来记录知识点,案例也跟着敲,不过不会有笔记记录了
# 为组件添加一个输入参数
输入属性 (opens new window)允许组件共享数据。数据共享的方向是从父组件到子组件。
- 要导入Input装饰器
import {Component, Input} from '@angular/core';
import {CommonModule} from '@angular/common';
添加Input属性
在属性名称后面添加一个
!
,并在前面加上@Input()
装饰器export class HousingLocationComponent { @Input() housingLocation!: HousingLocation; }
必须添加
!
,因为输入框期望传递一个值。在这种情况下,没有默认值。
向组件模板添加一个属性绑定
属性绑定使你能够将一个变量连接到 Angular 模板中的一个 Input
。然后,数据会动态绑定到 Input
中
当向组件标签添加属性绑定时,我们使用 [attribute] = "value"
语法来通知 Angular 所赋的值应该视为来自组件类的属性,而不是字符串值。
右侧的值是从 HomeComponent
中属性的名称。
# 向组件模板添加插值
使用插值在模板中显示值(属性和 Input
值)。
在 Angular 模板中使用 ,可以从属性、
Inputs
和有效的 JavaScript 表达式中渲染值。
# 使用*ngFor在组件中列出对象
在 Angular 中, ngFor
是一种特定类型的 指令 (opens new window),用于在模板中动态重复数据。在纯 JavaScript 中,你会使用 for 循环 — ngFor 为 Angular 模板提供了类似的功能。
你可以利用 ngFor
迭代数组,甚至是异步值。
# Angular 服务
Angular 服务为你提供了一种分离 Angular 应用程序数据和功能的方法,这些数据和功能可由应用程序中的多个组件使用。要被多个组件使用,服务必须是可注入的。由组件注入和使用的服务就成了该组件的依赖项。该组件依赖于这些服务,没有它们就无法运行。
依赖注入
依赖注入是一种用于管理应用程序组件和其他组件可以使用的服务的依赖关系的机制。
行此命令以创建新服务
ng generate service housing --skip-tests
新的服务添加静态数据,从
HomeComponent
复制housingLocationList
变量及其数组值。写如下的函数允许依赖项访问服务的数据。
getAllHousingLocations(): HousingLocation[] { return this.housingLocationList; } getHousingLocationById(id: number): HousingLocation | undefined { return this.housingLocationList.find((housingLocation) => housingLocation.id === id); }
别忘了导入housinglocation.ts的接口
将新服务注入到
HomeComponent
在
home.component.ts
添加inject
到从@angular/core
导入的条目中。import {Component, inject} from '@angular/core';
为
HousingService
添加一个新的文件级导入从
HomeComponent
中删除housingLocationList
数组条目,并将housingLocationList
赋值为空数组 ([]
),后面更新代码以从HousingService
中获取数据。在
HomeComponent
中,添加以下代码以注入新的服务并初始化应用的数据。constructor
是创建此组件时运行的第一个函数。constructor
中的代码将housingLocationList
赋值为调用getAllHousingLocations
返回的值。housingService: HousingService = inject(HousingService); constructor() { this.housingLocationList = this.housingService.getAllHousingLocations(); }
# 向应用添加路由
路由是从应用中的一个组件导航到另一个组件的能力。在 单页应用(SPA) (opens new window) 中,只有页面的部分内容会更新,以呈现用户请求的视图。
Angular 路由器 (opens new window)允许用户声明路由,并指定当应用请求该路由时应在屏幕上显示的组件。
创建默认的详情组件
ng generate component details
为应用添加路由
在
src/app
目录中,创建一个名为routes.ts
的文件。该文件是我们将在应用程序中定义路由的地方添加文件级别的导入。定义一个名为
routeConfig
的变量,其类型为Routes
,并为应用定义两个路由:import {Routes} from '@angular/router'; import {HomeComponent} from './home/home.component'; import {DetailsComponent} from './details/details.component'; const routeConfig: Routes = [ { path: '', component: HomeComponent, title: 'Home page', }, { path: 'details/:id', component: DetailsComponent, title: 'Home details', }, ]; export default routeConfig;
在
main.ts
中,进行以下更新以在应用程序中启用路由:导入路由文件和
provideRouter
函数:import {provideRouter} from '@angular/router'; import routeConfig from './app/routes';
更新对
bootstrapApplication
的调用以包含路由配置:bootstrapApplication(AppComponent, { providers: [provideProtractorTestingSupport(), provideRouter(routeConfig)], }).catch((err) => console.error(err));
在
src/app/app.component.ts
中,更新组件以使用路由:为
RoutingModule
添加文件级导入:import {RouterModule} from '@angular/router';
在
@Component
元数据的 imports 中添加RouterModule
imports: [HomeComponent, RouterModule],
在
template
属性中,用<router-outlet>
指令替换<app-home></app-home>
标签,并添加一个返回主页的链接template: ` <main> <a [routerLink]="['/']"> <header class="brand-name"> <img class="brand-logo" src="/assets/logo.svg" alt="logo" aria-hidden="true" /> </header> </a> <section class="content"> <router-outlet></router-outlet> </section> </main> `
# 带参数路由
路由参数使你能够将动态信息作为路由 URL 的一部分。
:id
是动态的,并且会根据代码请求路由的方式而变化。
在
src/app/housing-location/housing-location.component.ts
中,向section
元素添加一个锚标签,并包含routerLink
指令:<a [routerLink]="['/details', housingLocation.id]">Learn More</a>
routerLink
指令使 Angular 的路由器能够在应用中创建动态链接.赋予routerLink
的值是一个包含两部分的数组:路径的静态部分和动态数据。注意导入模块:
获取路由参数
在
src/app/details/details.component.ts
中更新模板以导入你需要在DetailsComponent
中使用的函数、类和服务:import {Component, inject} from '@angular/core'; import {CommonModule} from '@angular/common'; import {ActivatedRoute} from '@angular/router'; import {HousingService} from '../housing.service'; import {HousingLocation} from '../housinglocation';
更新以下代码:
自定义DetailComponent 添加对
HousingService
的调用把模板代码更新成这样:
template: ` <article> <img class="listing-photo" [src]="housingLocation?.photo" alt="Exterior photo of {{ housingLocation?.name }}" crossorigin /> <section class="listing-description"> <h2 class="listing-heading">{{ housingLocation?.name }}</h2> <p class="listing-location">{{ housingLocation?.city }}, {{ housingLocation?.state }}</p> </section> <section class="listing-features"> <h2 class="section-heading">About this housing location</h2> <ul> <li>Units available: {{ housingLocation?.availableUnits }}</li> <li>Does this location have wifi: {{ housingLocation?.wifi }}</li> <li>Does this location have laundry: {{ housingLocation?.laundry }}</li> </ul> </section> </article> `,
把
DetailsComponent
类的主体更新成这样:export class DetailsComponent { route: ActivatedRoute = inject(ActivatedRoute); housingService = inject(HousingService); housingLocation: HousingLocation | undefined; constructor() { const housingLocationId = Number(this.route.snapshot.params['id']); this.housingLocation = this.housingService.getHousingLocationById(housingLocationId); } }
样式代码:
.listing-photo { height: 600px; width: 50%; object-fit: cover; border-radius: 30px; float: right; } .listing-heading { font-size: 48pt; font-weight: bold; margin-bottom: 15px; } .listing-location::before { content: url('/assets/location-pin.svg') / ''; } .listing-location { font-size: 24pt; margin-bottom: 15px; } .listing-features > .section-heading { color: var(--secondary-color); font-size: 24pt; margin-bottom: 15px; } .listing-features { margin-bottom: 20px; } .listing-features li { font-size: 14pt; } li { list-style-type: none; } .listing-apply .section-heading { font-size: 18pt; margin-bottom: 15px; } label, input { display: block; } label { color: var(--secondary-color); font-weight: bold; text-transform: uppercase; font-size: 12pt; } input { font-size: 16pt; margin-bottom: 15px; padding: 10px; width: 400px; border-top: none; border-right: none; border-left: none; border-bottom: solid .3px; } @media (max-width: 1024px) { .listing-photo { width: 100%; height: 400px; } }
为HomeComponent添加导航
确认你的
AppComponent
的模板代码与以下内容一致imports: [HomeComponent, RouterLink, RouterOutlet], template: ` <main> <a [routerLink]="['/']"> <header class="brand-name"> <img class="brand-logo" src="/assets/logo.svg" alt="logo" aria-hidden="true" /> </header> </a> <section class="content"> <router-outlet></router-outlet> </section> </main> `,
# 集成Angular表单
向服务
housing.service.ts
添加一个方法来接收数据和打印数据到控制台,将此方法粘贴到类定义的底部submitApplication(firstName: string, lastName: string, email: string) { console.log( `Homes application received: firstName: ${firstName}, lastName: ${lastName}, email: ${email}.`, ); }
在详情页添加表单功能
在文件顶部的
import
语句之后,添加以下代码以导入 Angular 表单类import {FormControl, FormGroup, ReactiveFormsModule} from '@angular/forms';
在
DetailsComponent
装饰器的元数据中,使用以下代码更新imports
属性:imports: [CommonModule, ReactiveFormsModule],
在
DetailsComponent
类中的constructor()
方法之前,添加以下代码以创建表单对象applyForm = new FormGroup({ firstName: new FormControl(''), lastName: new FormControl(''), email: new FormControl(''), });
在 Angular 中,
FormGroup
和FormControl
是用于构建表单的类型。FormControl
类型可以提供默认值并形成表单数据。在此示例中,firstName
是一个string
,默认值为空字符串。在
DetailsComponent
类中的constructor()
方法之后,添加以下代码来处理 Apply now 的点击事件submitApplication() { this.housingService.submitApplication( this.applyForm.value.firstName ?? '', this.applyForm.value.lastName ?? '', this.applyForm.value.email ?? '', ); }
此代码使用空值合并运算符,如果值为
null
,则默认为空字符串。
将表单的标记添加到详情页
在
DetailsComponent
装饰器的元数据中,把template
的 HTML 更新成如下代码,以添加表单的标记template: ` <article> <img class="listing-photo" [src]="housingLocation?.photo" alt="Exterior photo of {{ housingLocation?.name }}" crossorigin /> <section class="listing-description"> <h2 class="listing-heading">{{ housingLocation?.name }}</h2> <p class="listing-location">{{ housingLocation?.city }}, {{ housingLocation?.state }}</p> </section> <section class="listing-features"> <h2 class="section-heading">About this housing location</h2> <ul> <li>Units available: {{ housingLocation?.availableUnits }}</li> <li>Does this location have wifi: {{ housingLocation?.wifi }}</li> <li>Does this location have laundry: {{ housingLocation?.laundry }}</li> </ul> </section> <section class="listing-apply"> <h2 class="section-heading">Apply now to live here</h2> <form [formGroup]="applyForm" (submit)="submitApplication()"> <label for="first-name">First Name</label> <input id="first-name" type="text" formControlName="firstName" /> <label for="last-name">Last Name</label> <input id="last-name" type="text" formControlName="lastName" /> <label for="email">Email</label> <input id="email" type="email" formControlName="email" /> <button type="submit" class="primary">Apply now</button> </form> </section> </article> `,
# 表单搜索
在 input
元素中包含一个名为 #filter
的模板变量
# 添加HTTP通信
将 HTTP 和 API 集成到应用程序中,让应用程序通过 HTTP 与 JSON 服务器通信
配置JSON服务器
JSON Server 是一种用于创建模拟 REST API 的开源工具
使用以下命令从 npm 安装
json-server
npm install -g json-server
在项目的根目录中,创建一个名为
db.json
的文件。这是你将存储json-server
数据的地方。打开
db.json
并将以下代码复制到文件中{ "locations": [ { "id": 0, "name": "Acme Fresh Start Housing", "city": "Chicago", "state": "IL", "photo": "${this.baseUrl}/bernard-hermant-CLKGGwIBTaY-unsplash.jpg", "availableUnits": 4, "wifi": true, "laundry": true }, { "id": 1, "name": "A113 Transitional Housing", "city": "Santa Monica", "state": "CA", "photo": "${this.baseUrl}/brandon-griggs-wR11KBaB86U-unsplash.jpg", "availableUnits": 0, "wifi": false, "laundry": true }, { "id": 2, "name": "Warm Beds Housing Support", "city": "Juneau", "state": "AK", "photo": "${this.baseUrl}/i-do-nothing-but-love-lAyXdl1-Wmc-unsplash.jpg", "availableUnits": 1, "wifi": false, "laundry": false }, { "id": 3, "name": "Homesteady Housing", "city": "Chicago", "state": "IL", "photo": "${this.baseUrl}/ian-macdonald-W8z6aiwfi1E-unsplash.jpg", "availableUnits": 1, "wifi": true, "laundry": false }, { "id": 4, "name": "Happy Homes Group", "city": "Gary", "state": "IN", "photo": "${this.baseUrl}/krzysztof-hepner-978RAXoXnH4-unsplash.jpg", "availableUnits": 1, "wifi": true, "laundry": false }, { "id": 5, "name": "Hopeful Apartment Group", "city": "Oakland", "state": "CA", "photo": "${this.baseUrl}/r-architecture-JvQ0Q5IkeMM-unsplash.jpg", "availableUnits": 2, "wifi": true, "laundry": true }, { "id": 6, "name": "Seriously Safe Towns", "city": "Oakland", "state": "CA", "photo": "${this.baseUrl}/phil-hearing-IYfp2Ixe9nM-unsplash.jpg", "availableUnits": 5, "wifi": true, "laundry": true }, { "id": 7, "name": "Hopeful Housing Solutions", "city": "Oakland", "state": "CA", "photo": "${this.baseUrl}/r-architecture-GGupkreKwxA-unsplash.jpg", "availableUnits": 2, "wifi": true, "laundry": true }, { "id": 8, "name": "Seriously Safe Towns", "city": "Oakland", "state": "CA", "photo": "${this.baseUrl}/saru-robert-9rP3mxf8qWI-unsplash.jpg", "availableUnits": 10, "wifi": false, "laundry": false }, { "id": 9, "name": "Capital Safe Towns", "city": "Portland", "state": "OR", "photo": "${this.baseUrl}/webaliser-_TPTXZd9mOo-unsplash.jpg", "availableUnits": 6, "wifi": true, "laundry": true } ] }
测试配置,在项目的根目录下运行以下命令
json-server --watch db.json
在你的 Web 浏览器中,导航到
http://localhost:3000/locations
并确认响应里包括存储在db.json
中的数据
更新服务以及组件以使用 Web 服务器而不是本地数组
数据源已配置,下一步是更新你的 Web 应用程序以连接到它来使用数据。
更新serve.ts
更新home.component.ts的constructor
constructor() { this.housingService.getAllHousingLocations().then((housingLocationList: HousingLocation[]) => { this.housingLocationList = housingLocationList; this.filteredLocationList = housingLocationList; }); }
更新details.component.ts的constructor
constructor() { const housingLocationId = parseInt(this.route.snapshot.params['id'], 10); this.housingService.getHousingLocationById(housingLocationId).then((housingLocation) => { this.housingLocation = housingLocation; }); }