十一月 5, 2018

[Angular2官方tutorial学习03]service,Observable data,Rxjs,asynchronous service,service in service

[Angular2官方tutorial学习03]service,Observable data,Rxjs,asynchronous service,service in service

官方的介绍有点文言文,但是对我来说,其实就是他把资料存取的部分独立到另外一个资料夹(类似像是MVC的Model资料夹),让整个代码的架构干净清洁,以下就开始介绍啰

@执行Angular CLI指令以新增一个服务, 服务名称叫做hero

ng g s hero

然后打开文件src\app\hero.service.ts,以下是预设的内容
内容中真正重要的部分就只有@Injectable注入的root关键字,是用来设定这个服务的可使用范围,而root的意思当然是整个应用程序范围都可以使用
实务上如果要缩小该服务的使用范围,再google一下Injectable的设定相关资讯即可,没必要现在全记

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

@Injectable({
  providedIn: 'root'
})
export class HeroService {

  constructor() { }
}

同样一个文件继续编辑,并且在HeroService的constructor下面加入下列代码

getHeroes(): Hero[] {
    return HEROES;
  }

加入完毕之后长这样子

@接着回到src/app/heroes/heroes.component.ts,把该import的加进去

import { HeroService } from '../hero.service';

而且原本的heros直接吃假资料heroes = HEROES;  
把他改成下面这样,纯粹宣告就好

heroes: Hero[];

然后把HeroesComponent的constructor改成下面这样,准备要Inject the HeroService注入服务

constructor(private heroService: HeroService) { }

再来于HeroesComponent的constructor的下面再加入一个method,来呼叫这个service

getHeroes(): void {
  this.heroes = this.heroService.getHeroes();
}

然后还是在src\app\heroes\heroes.component.ts,请在ngOnInit(){}里面呼叫服务以取得资料,如下
官网有稍微提醒ngOnInit()才是用来取得资料用的,constructor则是用来设定基本的class的设定档喔,别放错地方了!

ngOnInit() {
  this.getHeroes();
}

最后src\app\heroes\heroes.component.ts就会长的像是这样

此时再次打开浏览器,你会发现跟之前完全没两样,哈哈
不过的确把资料的存取独立到Service去,架构上会比较好拉

@接着要把取得资料的动作改成非同步的:在上面呼叫Service且取得资料的方式并不是Ajax,因此需将他改写成非同步的,想当然实务上可能在查询资料的时候,画面可能会有delay,下面步骤将会示范非同步的作法

@首先打开src/app/hero.service.ts,加入下列的import来使用Rxjs的函数库以呼叫相关的非同步method

import { Observable, of } from 'rxjs';

然后把里面原本的getHeros()这个method取代成如下。Observable就是Rxjs的关键字,他让整个method变成非同步的

getHeroes(): Observable<Hero[]> {
  return of(HEROES);
}

然后再打开src\app\heroes\heroes.component.ts,把里面原本宣告的getHeros(): void….改成如下
sbuscribe就是Rxjs的关键字,他让整个呼叫的过程变成非同步

getHeroes(): void {
  this.heroService.getHeroes()
      .subscribe(heroes => this.heroes = heroes);
}

最后src\app\heroes\heroes.component.ts代码长这样

最后src\app\hero.service.ts代码长这样

再次打开浏览器发现没什么不一样 XD
其实取得hero list的时候,已经改用非同步的了拉~

@接着再来练习稍微不同的service的运用,首先再次执行下列angular cli指令以新增另一个component

ng g c messages

产生component完毕之后,打开/src/app/app.component.html,请将原本的下列内容

<h1>{{title}}</h1>
<app-heroes></app-heroes>

修改成下面这样,用来测试新产生的component

<h1>{{title}}</h1>
<app-heroes></app-heroes>
<app-messages></app-messages>

目前的进度下,打开浏览器会看到message component会位于画面的最下方

然后再执行下列angular cli指令,新增另一个message service

ng g s message

打开/src/app/message.service.ts,将整个内容修改如下
add()是把资料push到变数阵列中(即把资料push到cache里面),而clear()就是清空变数阵列(即清空cache)

import { Injectable } from '@angular/core';
 
@Injectable({
  providedIn: 'root',
})
export class MessageService {
  messages: string[] = [];
 
  add(message: string) {
    this.messages.push(message);
  }
 
  clear() {
    this.messages = [];
  }
}

接着打开/src/app/hero.service.ts,加入下列import,我们打算在hero service里面呼叫message service

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

在同一个文件,把constructor改成如下,表示要message service及将要在hero service里面呼叫

constructor(private messageService: MessageService) { }

同一个文件里面,再去修改getHeroes()这个method,return的部分不变,但是额外多了this.messageService.add(‘HeroService: fetched heroes’);
把一段讯息加入到message service的cache里面了

getHeroes(): Observable<Hero[]> {
  // TODO: send the message _after_ fetching the heroes
  this.messageService.add('HeroService: fetched heroes');
  return of(HEROES);
}

再来打开src/app/messages/messages.component.html,修改整个内容如下,这是用来显示所有在message service里面的变数阵列

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

  <h2>Messages</h2>
  <button class="clear"
          (click)="messageService.clear()">clear</button>
  <div *ngFor='let message of messageService.messages'> {{message}} </div>

</div>

最后这个步骤最重要,请打开/src/app/messages/messages.component.ts,并加入下列import以及修改constructor
因为刚才我们在src/app/messages/messages.component.html里面,直接使用message service,因此必须在下面的constructor里面宣告message service为public

import { MessageService } from '../message.service';
constructor(public messageService: MessageService) {}

我们回头打开src\app\heroes\heroes.component.html来比较一下,这边他只有使用变数,并非直接使用hero service

也因此在src\app\heroes\heroes.component.ts里面的constructor无须宣告hero service为public

大概是这样……下面是浏览器目前的画面,虽然不重要 XD
但是还是贴一下截图吧

目前为止的进度的整个项目档提供给大家下载啰,放在dropbox
https://www.dropbox.com/s/1em2z6czkhsxiah/angular-tour-of-heros%20-%20%E5%AE%8C%E6%88%90service.rar?dl=0

参考资料:
[Angular2官方tutorial学习02]display list,master detail,click event,master detail advanced,帮css设定加上if
https://dotblogs.com.tw/kevinya/2018/10/26/105353
Services – Angular official tutorial
https://angular.io/tutorial/toh-pt4

本文永久链接:https://mrcpp.com/?p=96510,转载请注明出处

-- EOF --

相关文章 »