[KATA] 用 TypeScript 作一個簡易的 TodoList (二) - 用JQuery實作

設計理念

  1. 顯示/新增/刪除 TodoList
  2. TodoList 會是一堆 todoItem 的集合,所以要定義 todoItem 的形別
    • Content : todoItem 的內容
    • Status : todoItem 的狀態,完成(done)、未完成(undo) ,設計成列舉
  3. 主要的功能
    • 建立 todoItem
    • 完成 todoItem
    • 繪製 todoList 到前端的畫面上

自我分析

跟 UI 耦合太高,Render 應該與 TodoService 分離 ,
DOM 註冊事件相依在 Service 裡面要抽離也不好抽 。
沒有先寫測試 , 要想一想怎麼與 UI 層作隔離。

程式碼

建立 BaseService

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class BaseService<T> {
constructor(private type: string) {}

List: Array<T>;

Create(data: T) {
this.List.push(data);
}

Delete(data: T) {
var index = this.List.indexOf(data);
this.List.splice(index, 1);
}

Render() {}
}

建立 todoItem interface

1
2
3
4
interface todoItem {
Content: string;
Status: todoStatus;
}

建立 todoItem Status 列舉

1
2
3
4
enum todoStatus {
undo,
done,
}

建立 TodoService

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
class TodoService extends BaseService<todoItem> {
constructor() {
super("todoItem");
}

public Render(): void {
let doneHtml = "";
let undoHtml = "";

this.List.forEach((item) => {
if (item.Status == todoStatus.done) {
doneHtml += `<li>${item.Content}<button class="recover-item btn btn-default btn-xs pull-right"><span class="glyphicon glyphicon-share-alt"></span></button><button class="remove-item btn btn-default btn-xs pull-right"><span class="glyphicon glyphicon-remove"></span></button></li>`;
} else if (item.Status == todoStatus.undo) {
undoHtml += `<li class="ui-state-default"><div class="checkbox"><label><input type="checkbox" value="" />${item.Content}</label></div></li>`;
}
});
$("#done-items").html(doneHtml);
$("#sortable").html(undoHtml);
$(".add-todo").val("");
}

Delete(data: todoItem) {
data.Status = todoStatus.done;
}

Init() {
//// todoList in localStorage
var list = window.localStorage.getItem("todoList");
if (!list) {
this.List = new Array<todoItem>();
} else {
this.List = JSON.parse(list);
}
window.onbeforeunload = (evt) => {
window.localStorage.setItem("todoList", JSON.stringify(this.List));
};

// mark task as done
$(".todolist").on(
"change",
'#sortable li input[type="checkbox"]',
(evt) => {
var self = evt.target;
var text = $(self).parent().text();
if ($(self).prop("checked")) {
var doneItem = this.List.filter((i) => {
return text == i.Content;
})[0];
this.Delete(doneItem);
this.Render();
}
}
);

$(".add-todo").on("keypress", (evt) => {
evt.preventDefault;
if (evt.which == 13) {
if ($(evt.target).val() != "") {
var todo = $(evt.target).val();
this.Create({
Content: $(evt.target).val(),
Status: todoStatus.undo,
});
this.Render();
} else {
// some validation
}
}
});

$(".todolist").on("click", "#done-items li button.recover-item", (evt) => {
var text = $(evt.target).parent().parent().text();
var recoverItem = this.List.filter((i) => {
return text == i.Content;
})[0];
recoverItem.Status = todoStatus.undo;
this.Render();
});

$(".todolist").on("click", "#done-items li button.remove-item", (evt) => {
var text = $(evt.target).parent().parent().text();
var removeItem = this.List.filter((i) => {
return text == i.Content;
})[0];
var index = this.List.indexOf(removeItem);
this.List.splice(index, 1);
this.Render();
});

$("#checkAll").on("click", (evt) => {
this.List.forEach((item) => {
item.Status = todoStatus.done;
});
this.Render();
});

//// Render
this.Render();
}
}

使用建立好的 TodoService

1
2
var todoService = new TodoService();
todoService.Init();

(fin)

Please enable JavaScript to view the Gitalk. :D
Please enable JavaScript to view the LikeCoin. :P
Please enable JavaScript to view the LikeCoin. :P