原文连接:hacking-with-angularhtml
这篇文章咱们来说解如何使用service(服务)
,谈及服务咱们就要了解什么是服务;在Angular
中,咱们所说的服务是指那些可以被其它的组件或者指令调用的单一的,可共享的代码块.服务可以使咱们提升代码的利用率,方便组件之间共享数据和方法,方便测试和维护.git
若是你看了上一篇文章Step 5 - Dependency Injection,你就会发现咱们这一部分讲解的内容和上一篇有不少的类似之处;固然也有一些新的知识点,温故而知新嘛;好了让咱们来开始今天的旅行吧.es6
首先咱们仍是切换回以前的quickstart版本,而后运行:github
npm run start
能够看到My First Angular2 Travel
,而后继续咱们的铺垫工做;主要是三个部分:
1.将咱们的组件模板使用单一的html
模板来替代;
2.构建User
类方便咱们后面的使用;
3.构建咱们的模拟数据,方便咱们使用服务来获取这些数据;typescript
首先咱们来完成第一部分,修改app.component.ts
中@Component
的元数据:改成:template: '<h1>My First Angular2 Travel</h1>'
templateUrl: 'app/templates/main.html'
,而后咱们在main.html
中书写咱们的模板代码:npm
<h1>My First Angular2 Travel</h1>
而后咱们来进行第二个工做,建立咱们的User
类;为了展现方便,咱们就给User
两个属性吧,一个是id(number)
,一个是name(string)
;文件的路径是:app/classes/User.ts
,具体的代码以下:数组
export class User { //id: number; //name: string; constructor( private id: number, private name: string ){} }
上面注释的部分是这个User
类的简写,这个根据我的的喜爱;你喜欢写就怎么写.promise
最后一项工做就是来创造咱们的模拟数据,咱们如今尚未学习如何在Angular2
中使用HTTP
,因此咱们暂时将这些数据记录在一个文件中,而后导出这些数据,供咱们接下来使用.咱们的模拟数据文件路径是:app/mock/user.data.ts
;下面是代码部分:浏览器
import {User} from "../classes/User"; export const USERS: User[] = [ {id: 1, name: 'dreamapple1'}, {id: 2, name: 'dreamapple2'}, {id: 3, name: 'dreamapple3'}, {id: 4, name: 'dreamapple4'}, {id: 5, name: 'dreamapple5'}, {id: 6, name: 'dreamapple6'}, {id: 7, name: 'dreamapple7'}, {id: 8, name: 'dreamapple8'} ];
能够看到,咱们导出了一个数组,这个数组的每个元素都是一个User
类的实例.bash
接下来,咱们就要步入今天的主题了;构建一个服务,这个服务可以获取咱们刚刚书写的模拟数据;首先不要忘记的是,service
是一个类,而后这个类能够注入到别的组件
或者指令中去,还有一点就是咱们知道,获取数据的服务每每都是异步的,因此咱们使用了Promise
去封装咱们获取到的数据,来模拟异步请求;文件的路径是:app/service/user.service.ts
,咱们也遵循一个约定,服务的文件后缀是*.service.ts
,前面的单词若是是多个的话就使用短横线来链接,好比SpecialUserService
咱们就写成special-user.service.ts
,详细的部分请看代码:
import {User} from "../classes/User"; import {USERS} from "../mock/user.data"; export class UserService { getUsers(): User[] { return Promise.resolve(USERS); } }
关于上面代码的一些解释:由于咱们的getUsers
函数是有返回值的,它的返回值是一个数组,数组的每个元素都是User
类的实例,因此咱们使用了getUsers(): User[]
,还有由于咱们要模拟异步请求获取数据,因此咱们使用了Promise
,若是你对Promise
有什么不懂的地方,能够看看这里.
接下来咱们就要使用这个服务了,如何使用这个服务呢?在上一章节中咱们已经讲解了许多种使用服务的方法;如今咱们使用最简单的一种方式,直接使用providers
来注入咱们的服务,而后咱们还要把咱们获取到的数据展现到咱们的模板中,具体的代码以下所示:
import {Component} from '@angular/core'; import {User} from "./classes/User"; import {UserService} from "./services/user.service"; /* * 别忘记了使用@前缀 * 这里至关于组件视图 */ @Component({ selector: 'my-app', //template: '<h1>My First Angular2 Travel</h1>', templateUrl: 'app/templates/main.html', providers: [UserService] }) /* * 导出这个组件,也就是一个类 * 这里至关于组件控制器 */ export class AppComponent { users: User[]; constructor(private userService: UserService){ //noinspection TypeScriptUnresolvedFunction this.userService.getUsers().then( users => this.users = users ) } }
咱们也要改动main.html
的内容:
<h1>My First Angular2 Travel</h1> <ul> <li *ngFor="let user of users">{{user.name}}</li> </ul>
这时咱们打开浏览器,就会看到咱们想要的结果:
上面的写法是有一些问题的,构造函数是为了简单的初始化工做而设计的,好比把构造函数的参数赋值给属性.它的负担不该该过于沉重.因此咱们把数据的获取放在了组件的生命周期的钩子函数中去,若是你不了解组件的生命周期的话,那么你能够看看这里,在这里咱们使用了ngOnInit
;咱们修改一下上面的代码:
import {Component, OnInit} from '@angular/core'; import {User} from "./classes/User"; import {UserService} from "./services/user.service"; /* * 别忘记了使用@前缀 * 这里至关于组件视图 */ @Component({ selector: 'my-app', //template: '<h1>My First Angular2 Travel</h1>', templateUrl: 'app/templates/main.html', providers: [UserService] }) /* * 导出这个组件,也就是一个类 * 这里至关于组件控制器 */ export class AppComponent implements OnInit{ users: User[]; constructor( private userService: UserService ){} getUsersData() { this.userService.getUsers() .then(users => this.users = users); } ngOnInit() { this.getUsersData(); } }
上面代码的一些解释,首先咱们在@angular/core
中导出了OnInit
这个接口,而后咱们又经过组件中的ngOnInit
方法实现了这个接口;将构造函数中的获取数据的业务提取了出来,这种作法是组件初始化的时候获取数据比较好的一种方案.咱们在后面的文章中也会讲解关于组件或者指令生命周期的文章.
最后,咱们还能够更真实的的去模拟从服务器读取数据的操做;咱们能够经过使用setTimeout
来延时获取咱们的数据,这就很好地模拟了咱们从服务器获取数据的操做;具体的代码部分看下面:
import {User} from "../classes/User"; import {USERS} from "../mock/user.data"; export class UserService { getUsers(): Promise<User[]> { return Promise.resolve(USERS); } getMockUsers(): Promise<User[]> { return new Promise(resolve => setTimeout(resolve(USERS), 2000)) .then(() => this.getUsers()); } }
首先须要注意的一点是,咱们以前写的代码把getUsers()
函数的返回值定义为User[]
,其实更准确的应该是Promise<User[]>
;咱们接下来写的函数getMockUsers()
利用setTimeout
延时返回了咱们的模拟数据.
其实咱们的程序里还有一个小错误,不容易被发现;当我在构建的时候我发现了下面的错误:
它提醒咱们说,Property 'id' is private in type 'User' but not in type '{ id: number; name: string; }'.
这是由于咱们把id
做为User
的私有属性了,可是在{ id: number; name: string; }
对象中,id
不是私有的属性;要解决这个问题有多种思路,你能够将咱们的模拟数据使用User
类来建立,或者将id
和name
做为public
属性.那咱们就取一个简单的方法,将属性定义为public
.User
类的代码修改以下:
export class User { id: number; name: string; //constructor( // private id: number, // private name: string //){} }
在TypeScript里,每一个成员默认为是public的.因此上面的写法是很简便的.
到这里咱们要说的内容已经说完了,源代码能够参考这里angular2-travel,固然欢迎批评指正.