-
Notifications
You must be signed in to change notification settings - Fork 622
Expand file tree
/
Copy pathtodo-list.ts
More file actions
70 lines (60 loc) · 2.5 KB
/
todo-list.ts
File metadata and controls
70 lines (60 loc) · 2.5 KB
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
import { Context } from "@microsoft/fast-element/context.js";
import { Observable, observable } from "@microsoft/fast-element/observable.js";
import { reactive } from "@microsoft/fast-element/state.js";
import { volatile } from "@microsoft/fast-element/volatile.js";
export type Todo = { description: string; done: boolean };
export type TodoListFilter = "all" | "active" | "completed";
export const TodoList = Context.create<TodoList>("TodoList");
export interface TodoList {
activeFilter: TodoListFilter;
readonly filtered: readonly Todo[];
add(description: string): void;
remove(todo: Todo): void;
}
export class DefaultTodoList {
@observable private _todos: Todo[] = [];
@observable public activeFilter: TodoListFilter = "all";
public get all() {
return this._todos;
}
@volatile
public get filtered(): readonly Todo[] {
// This property is decorated with @volatile because the exact
// observable dependencies of the property can change between
// invocations. Normally, FAST assumes that the dependencies of
// a binding are the same across invocations, for optimization
// purposes. So, in this case, we need to tell the system not to
// make that assumption.
switch (this.activeFilter) {
case "active":
return this._todos.filter(x => !x.done);
case "completed":
return this._todos.filter(x => x.done);
default:
return this._todos;
}
}
constructor(todos?: Todo[]) {
if (todos) {
this._todos = todos.map(x => reactive(x));
}
}
public add(description: string) {
this.splice(this._todos.length, 0, reactive({ description, done: false }));
}
public remove(todo: Todo) {
const index = this._todos.indexOf(todo);
index !== -1 && this.splice(index, 1);
}
/**
* This method centralizes all updates to the internal array so that we
* can guarantee that observers are notified in the appropriate cases.
*/
private splice(index: number, removeCount: number, ...newItem: Todo[]) {
this._todos.splice(index, removeCount, ...newItem);
// Because the filtered property returns different arrays depending
// on the filter, we need to notify FAST that the dependent _todos
// observable has changed whenever we splice the internal data structure.
this.activeFilter !== "all" && Observable.notify(this, "_todos");
}
}