Define Todo List page

Define Todo.List type (DefineList basics)

The problem

  • Define a Todo.List type on the export of models/todo.js, where:
    • It is a DefineList type.
    • The enumerable indexes are coerced into Todo types.
    • Its .active property returns a filtered Todo.List of the todos that are not complete.
    • Its .complete property returns a filtered Todo.List of the todos that are complete.
    • Its .allComplete property 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 Basics Presentation

  • 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;