Angular学习笔记9:服务(Service)(2)

可观察的对象(observable)的数据

在现在的是情况下:HeroService.getHeroes() 的函数签名是同步的,它所隐含的假设是 HeroService 总是能同步获取英雄列表数据。 而 HeroesComponent 也同样假设能同步取到 getHeroes() 的结果。但是在实际的项目中,这种情况几乎是不可能实现的,因为,在实际的项目中,这些数据是来源于远端的服务器上,而这个过程始终是一个异步的过程。

 在实际的项目中:HeroService 必须等服务器给出响应, 而 getHeroes() 不能立即返回英雄数据, 浏览器也不会在该服务等待期间停止响应。HeroService.getHeroes() 必须具有某种形式的异步函数签名。它可以使用回调函数,可以返回 Promise(承诺),也可以返回 Observable(可观察对象)。

一. 重新写一个可观察对象版本的 HeroService

Observable简介:Observable 是 RxJS中的一个关键类。

重写

1.打开 HeroService 文件,并从 RxJS 中导入 Observable 和 of 符号。

import { Observable, of } from 'rxjs';

2. 修改getHeroes 方法:

 
  1. getHeroes(): Observable<Hero[]> {

  2. return of(HEROES);

  3. }

注意:of(HEROES) 会返回一个 Observable<Hero[]>,它会发出单个值,这个值就是这些模拟英雄的数组。

3.在 HeroesComponent 中订阅 

之前的HeroService.getHeroes 方法返回的是一个 Hero[], 现在它返回的是 Observable<Hero[]>。所以现在必须在 HeroesComponent 中也向本服务中的这种Observable形式变化。

修改getHeroes():

 
  1. getHeroes(): void {

  2. this.heroService.getHeroes()

  3. .subscribe(heroes => this.heroes = heroes);

  4. }

Observable.subscribe() 是关键的差异点。

两个版本的差别:

第一个版本:

hero的数组赋值给了该组件的 heroes 属性。 这种赋值是同步的,这里包含的假设是服务器能立即返回hero数组或者浏览器能在等待服务器响应时冻结界面,使其等到后端的数据返回以后,界面在再次解冻。

第二个版本:

应用会等待Observable 发出这个hero数组,这种请求可能立即发生,也可能会在几分钟之后。 然后,subscribe 函数把这个hero数组传给这个回调函数,该函数把hero数组赋值给组件的 heroes 属性。使用这种异步方式,当 HeroService 从远端服务器获取hero数据时,应用就可以工作了。(此过程可以想像类似的想像于将界面暂时冻结,然后等到远端的服务器将需要的数据返回以后,自动的将界面又重新的解冻,使应用重新开始工作)

二. 显示信息

学习目标:

  • 添加一个 MessagesComponent,它在屏幕的底部显示应用中的消息。

  • 创建一个可注入的、全应用级别的 MessageService,用于发送要显示的消息。

  • 把 MessageService 注入到 HeroService 中。

  • 当 HeroService 成功获取了英雄数据时显示一条消息。

1.创建MessagesComponent(推荐使用CLI创建)

 
  1. wjydeMacBook-Pro:demo wjy$ ng generate component messages

  2. CREATE src/app/messages/messages.component.css (0 bytes)

  3. CREATE src/app/messages/messages.component.html (27 bytes)

  4. CREATE src/app/messages/messages.component.spec.ts (642 bytes)

  5. CREATE src/app/messages/messages.component.ts (277 bytes)

  6. UPDATE src/app/app.module.ts (638 bytes)

CLI 在 src/app/messages中创建了组件文件,并且把 MessagesComponent 声明在了 AppModule 中。

2.修改 AppComponent 的模板来显示所生成的 MessagesComponent

 
  1. <h1>{{title}}</h1>

  2. <app-heroes></app-heroes>

  3. <app-messages></app-messages>

<app-messages> 是MessagesComponent的  selector: 'app-messages'

3.创建 MessageService

 
  1. wjydeMacBook-Pro:demo wjy$ ng generate service messages

  2. CREATE src/app/messages.service.spec.ts (386 bytes)

  3. CREATE src/app/messages.service.ts (137 bytes)

4.在MessagesService中增加一个message的变量,并且在写一个新增message的方法和清空message的方法。

 
  1. import {Injectable} from '@angular/core';

  2.  
  3. @Injectable({

  4. providedIn: 'root'

  5. })

  6. export class MessageService {

  7.  
  8. // messages 变量

  9. messages: string[] = [];

  10.  
  11. // 增加变量的函数

  12. add(message: string) {

  13. this.messages.push(message);

  14. }

  15.  
  16. // 清空变量的函数

  17. clear() {

  18. this.messages = [];

  19. }

  20.  
  21. // 构造方法

  22. constructor() {

  23. }

  24. }

5.把它注入到 HeroService 中

打开 HeroService,将导入 MessageService

import { MessageService } from './message.service';

6.修改这个构造函数

添加一个私有的 messageService 属性参数。 Angular 将会在创建 HeroService 时把 MessageService 的单例注入到这个属性中。

constructor(private messageService: MessageService) { }

7.从 HeroService 中发送一条消息

修改 getHeroes 方法,在获取到英雄数组时发送一条消息。

 
  1. getHeroes(): Observable<Hero[]> {

  2. this.messageService.add('HeroService: fetched heroes');

  3. return of(HEROES);

  4. }

8.从 HeroService 中显示消息

打开 MessagesComponent,并且导入 MessageService

import { MessageService } from '../message.service';

修改MessagesComponent构造函数,添加一个 public 的 messageService 属性。 Angular 将会在创建 MessagesComponent 的实例时 把 MessageService 的实例注入到这个属性中。

此处设messageService为public是因为要在messageService在模版文件中用到。

注意:⚠️Angular只会绑定公共的属性

9.绑定到 MessageService

修改messageComponent的模版文件

 
  1. <div *ngIf="messageService.messages.length">

  2. <h2>Messages</h2>

  3. <button class="clear" (click)="messageService.clear()">clear

  4. </button>

  5. <div *ngFor='let message of messageService.messages'> {{message}}</div>

  6. </div>

  • *ngIf 只有在有消息时才会显示消息区。

  • *ngFor用来在一系列 <div> 元素中展示消息列表。

  • Angular 的事件绑定把按钮的 click 事件绑定到了 MessageService.clear()这个方法上了

10.保存运行,刷新浏览器,界面如下

11.使Message更好看点

为MessagesComponent组件添加私有样式

 
  1. h2 {

  2. color: red;

  3. font-family: Arial, Helvetica, sans-serif;

  4. font-weight: lighter;

  5. }

  6. body {

  7. margin: 2em;

  8. }

  9. body, input[text], button {

  10. color: crimson;

  11. font-family: Cambria, Georgia;

  12. }

  13.  
  14. button.clear {

  15. font-family: Arial;

  16. background-color: #eee;

  17. border: none;

  18. padding: 5px 10px;

  19. border-radius: 4px;

  20. cursor: pointer;

  21. cursor: hand;

  22. }

  23. button:hover {

  24. background-color: #cfd8dc;

  25. }

  26. button:disabled {

  27. background-color: #eee;

  28. color: #aaa;

  29. cursor: auto;

  30. }

  31. button.clear {

  32. color: #888;

  33. margin-bottom: 12px;

  34. }

猜你喜欢

转载自blog.csdn.net/plpldog/article/details/82992606