掌握Angular2的服務(service)

原文連接: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>

這時咱們打開瀏覽器,就會看到咱們想要的結果:
service

上面的寫法是有一些問題的,構造函數是爲了簡單的初始化工做而設計的,好比把構造函數的參數賦值給屬性.它的負擔不該該過於沉重.因此咱們把數據的獲取放在了組件的生命週期的鉤子函數中去,若是你不瞭解組件的生命週期的話,那麼你能夠看看這裏,在這裏咱們使用了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延時返回了咱們的模擬數據.

其實咱們的程序裏還有一個小錯誤,不容易被發現;當我在構建的時候我發現了下面的錯誤:
services

它提醒咱們說,Property 'id' is private in type 'User' but not in type '{ id: number; name: string; }'.這是由於咱們把id做爲User的私有屬性了,可是在{ id: number; name: string; }對象中,id不是私有的屬性;要解決這個問題有多種思路,你能夠將咱們的模擬數據使用User類來建立,或者將idname做爲public屬性.那咱們就取一個簡單的方法,將屬性定義爲public.User類的代碼修改以下:

export class User {
    id: number;
    name: string;

    //constructor(
    //    private id: number,
    //    private name: string
    //){}
}

在TypeScript裏,每一個成員默認爲是public的.因此上面的寫法是很簡便的.

到這裏咱們要說的內容已經說完了,源代碼能夠參考這裏angular2-travel,固然歡迎批評指正.

相關文章
相關標籤/搜索