Define Todo List page
Define Todo.List type (DefineList basics)
The problem
- Define a
Todo.Listtype on the export of models/todo.js, where:- It is a DefineList type.
- The enumerable indexes are coerced into
Todotypes. - Its
.activeproperty returns a filteredTodo.Listof the todos that are not complete. - Its
.completeproperty returns a filteredTodo.Listof the todos that are complete. - Its
.allCompleteproperty true if all the todos are complete.
Example test code:
QUnit.ok(Todo.List, "Defined a List");
const todos = new Todo.List([
{complete: true},
{},
{complete: true}
]);
QUnit.ok(todos[0] instanceof Todo, "each item in a Todo.List is a Todo");
QUnit.equal(todos.active.length, 1);
QUnit.equal(todos.complete.length, 2);
QUnit.equal(todos.allComplete, false, "not allComplete");
todos[1].complete = true;
QUnit.equal(todos.allComplete, true, "allComplete");
What you need to know
DefineList.extend defines a new
ListType.The # property defines the behavior of items in a list like:
DefineList.extend({ "#": {type: ItemType} })The get behavior defines observable computed properties like:
DefineMap.extend({ propertyName: { get: function() { return this.otherProperty; } } })filter can be used to filter a list into a new list:
list = new ListType([ // ... ]); list.filter(function(item) { return test(item); })
The solution
Click to see the solution
Update models/todo.js to the following:
// models/todo.js
import {DefineMap, DefineList} from "can";
const Todo = DefineMap.extend("Todo", {
id: "string",
name: "string",
complete: {
type: "boolean",
default: false
},
toggleComplete() {
this.complete = !this.complete;
}
});
Todo.List = DefineList.extend("TodoList", {
"#": Todo,
get active() {
return this.filter({
complete: false
});
},
get complete() {
return this.filter({
complete: true
});
},
get allComplete() {
return this.length === this.complete.length;
}
});
export default Todo;

