在Angular2 中導入Service 扮演 MVC 架構底下 Model 的角色
首先,透過Angular CLI 來替我們的Angular2專案加入Service
ng g s service\todo-list
(PS.Service命名的時候,不需要再TodoList後面加上Service,產生的檔案會自動命名多service)
例如上面這串Cli指令新增出來的檔案名稱為 todo-list.service.ts
檔案內容為:
import { Injectable } from '@angular/core';
import {ITodoItem} from '../interface/i-todo-item';
@Injectable()
//class Name會自動在後面補上Service
export class TodoListService {
  constructor() { }
}
因為要扮演MVC架構底下Model的腳色,所以接下來把資料處理的程式寫到剛剛新增的
todo-list.service.ts
import { Injectable } from '@angular/core';
import { ITodoItem } from '../interface/i-todo-item';
@Injectable()
export class TodoListService {
  
  todoItems: ITodoItem[] = [
    {
      id: 1,
      value: 'Todo Item No.1',
      done: false
    },
    {
      id: 2,
      value: 'Todo Item No.2',
      done: true
    },
    {
      id: 3,
      value: 'Todo Item No.3',
      done: false
    }
  ];
  constructor() { }
  getTodoList() {
    return this.todoItems;
  };
  addTodoListItem(text) {
    this.todoItems.push({
      id: (new Date()).getTime(),
      value: text,
      done: false
    });
  }
  delTodoListItem(paraObject: ITodoItem) {
    this.todoItems = this.todoItems.filter(function (ele) {
      return ((ele.id != paraObject.id) && (ele.value != paraObject.value));
    });
  }
  togoogleTodoItem(item: ITodoItem) {
    item.done = !item.done;
  }
}
Service定義好之後,要讓Service能夠被注入(其他component可以使用),
我們必須先在src/app/app.module.ts中的 @NgModule 這個 decorator 中的 providers: []中加入剛剛建立好的Service
//要記得 import Service
import { TodoListService } from './service/todo-list.service';
@NgModule({
  declarations: [
    AppComponent,
    AddFormComponent,
    HeaderComponent,
    TodoItemsComponent
  ],
  imports: [
    BrowserModule
  ],
  // 在providers中加入TodoListService
  providers: [TodoListService], 
  bootstrap: [AppComponent]
})
export class AppModule { }
補充說明:自動在Module註冊的CLI指令
如果想要產生Service的時候自動在指定的Module註冊,可在後面加上 -m ModuleName
例如:
ng g s data -m article
這樣會產生一個service:data 並且幫我註冊到article 這一個Module

- 在Component中加入Service
接下來要做三件事情:
1.import 要使用的 Service。
2.在constructor 內宣告參數(注入方式為建構式注入),之後在Component的程式碼都能夠透過this.todoService 來取用這個service的資料。
3.依序將程式改為透過 this.todoService 控制
import { ITodoItem } from '../../interface/i-todo-item';
import { Component, OnInit } from '@angular/core';
//1.import 要使用的 Service
import { TodoListService } from '../../service/todo-list.service';
@Component({
  selector: 'app-todo-items',
  templateUrl: './todo-items.component.html',
  styleUrls: ['./todo-items.component.css']
})
export class TodoItemsComponent implements OnInit {
  //2.在constructor 內宣告參數,
  //之後在Component的程式碼都能夠透過this.todoService 來取用這個service的資料。
  constructor(private todoService: TodoListService) { }
  ngOnInit() {
  }
  //3.依序將程式改為透過 this.todoService 控制
  getTodoList() {
    return this.todoService.getTodoList();
  }
  delTodoItem(delItem: ITodoItem) {
    return this.todoService.delTodoListItem(delItem);
  }
  clickTodoList(item: ITodoItem) {
    return this.todoService.togoogleTodoItem(item);
  }
}
component.html 配合修正
<div class="container">
  <div class="row">
    <div class="col-sm-5 col-sm-offset-2 ">
      <ul>
        <li *ngFor="let item of getTodoList()">
          <label for="chk_{{item.id}}">
            <input type="checkbox" name="" id="" [checked]="item.done" (click)="clickTodoList(item)">{{item.value}}
          </label>
          <a href="#" (click)="delTodoItem(item)">Delete</a>
          <span *ngIf="item.done">(已完成)</span>
        </li>
      </ul>
    </div>
  </div>
</div>
在Module內注入Service的作法,也可以使用以下的宣告方式
todoService:TodoListService;
constructor(todoService: TodoListService) {
   this.todoService = todoService;
 }
上面的寫法則是TypeScript提供簡化後的寫法
constructor(private todoService: TodoListService) { }
PS.private 也可以宣告成public
不要在component 內儲存Service的資料內容
情境描述:
在service內定義了一個Array : data
在component.ts裡面我也定義了一個Array : data
在ngOnInit()的時候去儲存service內的data
constructor(public datasvc: DataService) {}
  data = Array();
  ngOnInit() {
    this.data = this.datasvc.data;
  }
這樣做會有一個問題,
service那邊的Array ,在做資料修改(刪除、修改)的時候,
如果是用產生"新"陣列的方式來產生新的陣列
保哥建議在修改陣列內容的時候,以重新產生陣列的方式(map+Object.assign)產生新的陣列)
EditData(post: any) {
    this.data = this.data.map(item => {
      if (item.id == post.id) {
        return Object.assign({}, item, post);
      }
      return item;
    });
  }
component這邊的ngOnInit()不會重新執行,所以重新產生的陣列跟component這邊的陣列就不是相同的物件了!
這樣不管使用者在Service內怎麼修改、刪除,資料都無法正常更新回component。
解決方法:直接存取service內的陣列就好!