Dowemo


Question:

As a learning exercise, I have a todo list with to do items. In my view, I would like to display the items grouped by completion. Below is my viewmodel. How would I go about doing what I want to achieve, how do I setup the computed observables?

         function TodoList(name, items) {


        this.name = ko.observable(name === "undefined"? "": name);


        this.todoItems = ko.observableArray(typeof (items) !== "undefined" ? items : []); 


    }



    function TodoItem(name,completed) {


        this.name = ko.observable(name === "undefined" ? "" : name);


        this.completed = ko.observable(completed === "undefined" ? false : completed);


    }



    function TodoListViewModel() {


        var self = this;


        self.todoLists = ko.observableArray([



            new TodoList("Groceries", [


                new TodoItem("Milk", true),


                new TodoItem("Bread",false),


                new TodoItem("Tissues",false)


            ]),


            new TodoList("Luggage", [


                new TodoItem("Hairdryer", false),


                new TodoItem("Toothbrush",false)


            ]),             


        ]);


    }



Best Answer:


  • Create a computed property in your TodoList viewmodel. Since the computed's method does not have any side effects, it's best to use a ko.pureComputed:

    this.completedItems = ko.pureComputed(function() { /* ... */ }, this);
    
    
    
  • Note: the second this parameter sets the current this context as the "owner" of the computed. I.e.: within the computed's method, this refers to the TodoList instance.

  • Within the computed's method, evaluate the todoItems observable array to create a subscription to its values:

    var currentItems = this.todoItems();
    
    
    
  • Filter the items by completed and return the array:

    return currentItems.filter(function(item) {
    
    
      return item.completed();
    
    
    });
    
    
    
  • Now, every TodoList has a computed array of completed items. You could create a list of uncompleted items in similar fashion.

    If you want to take it one step further and group completed items between lists, you can add a ko.pureComputed to your TodoListViewModel as well:

    this.allCompletedItems = ko.pureComputed(function() {
    
    
      return this.todoLists()
    
    
        .map(function(todoList) { return todoList.completedItems(); })
    
    
        .reduce(function(result, itemList) { return result.concat(itemList); }, []);
    
    
    }, this);
    
    
    

    All code together:

    function TodoList(name, items) {
    
    
      this.name = ko.observable(name === "undefined" ? "" : name);
    
    
      this.todoItems = ko.observableArray(typeof(items) !== "undefined" ? items : []);
    
    
    
      this.completedItems = ko.pureComputed(function() {
    
    
        return this.todoItems()
    
    
          .filter(function(item) {
    
    
            return item.completed();
    
    
          });
    
    
      }, this);
    
    
    }
    
    
    
    function TodoItem(name, completed) {
    
    
      this.name = ko.observable(name === "undefined" ? "" : name);
    
    
      this.completed = ko.observable(completed === "undefined" ? false : completed);
    
    
    }
    
    
    
    function TodoListViewModel() {
    
    
      this.todoLists = ko.observableArray([
    
    
        new TodoList("Groceries", [
    
    
          new TodoItem("Milk", true),
    
    
          new TodoItem("Bread", false),
    
    
          new TodoItem("Tissues", false)
    
    
        ]),
    
    
        new TodoList("Luggage", [
    
    
          new TodoItem("Hairdryer", false),
    
    
          new TodoItem("Toothbrush", false)
    
    
        ]),
    
    
      ]);
    
    
    
      this.allCompletedItems = ko.pureComputed(function() {
    
    
        return this.todoLists()
    
    
          .map(function(todoList) {
    
    
            return todoList.completedItems();
    
    
          })
    
    
          .reduce(function(result, itemList) {
    
    
            return result.concat(itemList);
    
    
          }, []);
    
    
      }, this);
    
    
    }
    
    
    



    Copyright © 2011 Dowemo All rights reserved.    Creative Commons   AboutUs