Angular 2 + Ionic = Mobile App ( 3 ) 實作 Todo List
- 2017-01-07
- Liu, An-Chi 劉安齊
建立專案
上回我們已經說明如何建立一個專案,而這次我們用經典的 Todo List (備忘錄) 來做說明
ionic start TODOApp blank --v2
blank
就是空白的模板
上回介紹過 Ionic 專案的架構,今天我們都會著重在 scr
的部分,也就是程式主幹。
成品
先看看結果
這邊可以看到我完成的專案
建立頁面
scr/pages
是我們的 App 裡面有的頁面,App 的各種畫面,就等同於網頁的各個頁面。
一個簡單的 TODO,包含:
- 首頁:呈現所有事項
- 細節:檢視詳細內容
- 增加:增加事項的畫面
空白專案已經有 scr/pages/home
了, home
就是我們的首頁,我們還缺一個 detail 跟 add
先 cd 進入 TODOApp 資料夾後,我們可以在終端機輸入
ionic generate page detail
generate 可以減寫成 g,自動產生 html、ts、scss 三個檔案
也可以手動輸入
mkdir app/pages/detail
touch app/pages/detail/detail.ts
touch app/pages/detail/detail.html
touch app/pages/detail/detail.scss
差別在於 ionic 指令會產生套好模板的文件,手動建立則是空白的。
接著
ionic generate page add
首頁 home
html
首先來看 app/pages/todos/home.html
,這是首頁的模板
<ion-header>
<ion-navbar>
<ion-title>Todo List</ion-title>
<ion-buttons end>
<button (click)="add()" ion-button icon-only><ion-icon name="add"></ion-icon></button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item-sliding *ngFor="let todo of todoList; let i = index;">
<button ion-item (click)="detail(i)">
<h2>{{ todo.title }}</h2>
</button>
<ion-item-options>
<button class="red" (click)="delete(i)">
<ion-icon name="trash"></ion-icon>
Delete
</button>
</ion-item-options>
</ion-item-sliding>
</ion-list>
</ion-content>
add()
是之後用來加入新事項的按鈕。
delete(i)
是之後用來刪掉的按鈕。
detail(i)
點進去可以看細節。
ts
一個畫面是一個組件,概念就是 Angular 2。
app/pages/todos/home.ts
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { AddPage } from "../add/add";
import { DetailPage } from "../detail/detail";
@Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
public todoList: Array<any> = [];
constructor(private navCtrl: NavController) { }
ionViewDidEnter() {
this.todoList = JSON.parse(localStorage.getItem("todos"));
console.log(this.todoList);
}
delete(index: number) {
this.todoList.splice(index, 1);
localStorage.setItem("todos", JSON.stringify(this.todoList));
}
add() {
this.navCtrl.push(AddPage);
}
detail(index: number){
this.navCtrl.push(DetailPage, {
id: index
});
}
}
AddPage
DetailPage
等等處理。
我們在 ionViewDidEnter()
才導入 localStorage 資料而非 constructor()
是因為前者可以讓我們每次進入畫面都觸發,而後者只有在被導向進來時才觸發 (如果按返回就沒事)。
資料部分簡單用 localStorage 以 json 來做儲存。當然你也可以用 DB 外掛來處理。
this.navCtrl.push()
可以導向其他頁面。例如 this.navCtrl.push(AddPage)
。也可以加上參數 this.navCtrl.push(DetailPage, {id: index});
。
增加事項的頁面 add
html
<ion-header>
<ion-navbar>
<ion-title>Add Item</ion-title>
<ion-buttons end>
<button (click)="save()" ion-button icon-only><ion-icon name="checkmark"></ion-icon></button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item>
<ion-label floating>Title</ion-label>
<ion-input type="text" [(ngModel)]="todoTitle"></ion-input>
</ion-item>
<ion-item>
<ion-label floating>Description</ion-label>
<ion-input type="text" [(ngModel)]="todoDes"></ion-input>
</ion-item>
</ion-list>
</ion-content>
floating
標籤可以讓文字飄上去。
ts
import { Component } from '@angular/core';
import { NavController} from 'ionic-angular';
@Component({
templateUrl: 'add.html'
})
export class AddPage {
public todoList: Array<any>;
public todoTitle: string;
public todoDes: string;
constructor(private navCtrl: NavController) {
this.todoList = JSON.parse(localStorage.getItem("todos"));
if(!this.todoList) {
this.todoList = [];
}
this.todoTitle = "";
this.todoDes = ""; // description
}
save() {
if(this.todoTitle != "" && this.todoDes != "") {
this.todoList.push(
{
title: this.todoTitle,
des: this.todoDes
}
);
localStorage.setItem("todos", JSON.stringify(this.todoList));
this.navCtrl.pop();
} else if(this.todoTitle == "") {
alert("No Title!");
} else if(this.todoDes == ""){
alert("No Description!");
}
}
}
todoTitle
todoDes
和模板雙向綁定,按下 save()
會儲存進 todos
查看細節頁面 detail
html
<ion-header>
<ion-navbar>
<ion-title>Detail</ion-title>
</ion-navbar>
<ion-buttons end>
<button (click)="close()" ion-button icon-only><ion-icon name="checkmark"></ion-icon></button>
</ion-buttons>
</ion-header>
<ion-content padding>
<ion-card>
<ion-card-header>
{{ title }}
</ion-card-header>
<ion-card-content>
{{ description }}
</ion-card-content>
</ion-card>
</ion-content>
<ion-header>
<ion-navbar>
<ion-title>Detail</ion-title>
<ion-buttons end>
<button (click)="close()"><ion-icon name="close"></ion-icon></button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content padding>
<ion-card>
<ion-card-header>
{{ title }}
</ion-card-header>
<ion-card-content>
{{ description }}
</ion-card-content>
</ion-card>
</ion-content>
ts
import { Component } from '@angular/core';
import { NavController, NavParams } from 'ionic-angular';
@Component({
selector: 'page-detail',
templateUrl: 'detail.html'
})
export class DetailPage {
public title: string;
public description: string;
constructor(public navCtrl: NavController, public navParams: NavParams) {
let id: number = navParams.get('id');
let todoList: any = JSON.parse(localStorage.getItem("todos"));
this.title = todoList[id].title;
this.description = todoList[id].des;
console.log(this.title);
}
ionViewDidLoad() {
//console.log('ionViewDidLoad DetailPage');
}
close(){
this.navCtrl.pop();
}
}
還記得剛剛在 home.ts
的 detail(i)
,我們再導入進來 detail
時候有輸入參數嗎?
這時候我們要 import { NavParams } from 'ionic-angular';
使用 NavParams
,就可以取得參數 let id: number = navParams.get('id');
。
SCSS
接著我們稍微修飾一下我們的外觀
打開 src/theme/variables.scss
這邊的 scss 會是全域變數。
$toolbar-ios-title-font-size: 2.3rem;
$toolbar-ios-height: 30px;
$font-family-base: Microsoft JhengHei, -apple-system, "Helvetica Neue", "Roboto", sans-serif !default;
預設標題真的很小,把標題變大一點。
打開 src/pages/home/home.scss
.danger{
background-color: #f53d3d;
color: white;
}
我們讓刪除的按鈕變成紅色的。
大功告成囉!
下回介紹如何輸出,實際放到手機上!