Sara
Sara

Reputation: 2769

ko.computed in KnockoutJS to do list app

I'm making a simple to do list app to learn KnockoutJS. Right now I can add a task, and when I click the 'Remove' link, the task is removed from the view. I have a count of tasks at the bottom that uses a ko.computed function. It updates when I add a task, but when I remove a task the number stays the same. Does anyone know what's wrong with the code below?

Here's my JS:

$(function() {
var Todo = function (task, complete) {
    this.task = task;
    this.complete = complete;
}

var AppViewModel = function(todos) {
    var self = this;

    //Create an observable array of Todo objects
    self.toDoItems = ko.observableArray([
        { task: "Learn KnockoutJS", complete: false}
    ]);



    //Add a new todo
    self.add = function() {
        self.toDoItems.push(new Todo($('.txt').val()));
        $('.txt').val('');
    };

    //Remove a todo
    self.remove = function(item) {
        self.toDoItems.destroy(item);
    }

    //Mark a todo complete
    self.complete = function (item) {
        item.complete = true;
    }


    //Count active tasks
    self.remainingTasks = ko.computed(function() {
        return self.toDoItems().length;
    })
}

ko.applyBindings(new AppViewModel());

});

And here's my view:

<h3>Tasks</h3>

<table>
<tbody data-bind="foreach: toDoItems">
    <tr>
      <td><input type="checkbox" data-bind="click: $root.complete"></td>
      <td class="todo-item"><label data-bind="text: task"></label></td>
      <td class="remove"><a href="#" data-bind="click: $root.remove">Remove</a></td>
    </tr>
 </tbody>
 </table>
 <br>
 <input class="txt" />
 <button data-bind="click: add">Add</button><br><br>
 There are <strong data-bind="text: remainingTasks"></strong> tasks here.<br>

Upvotes: 0

Views: 230

Answers (2)

Niko
Niko

Reputation: 26730

knockout observable arrays implement two ways to delete items: remove(), which actually removes the item from the array, and destroy(), which just marks the items as "destroyed" but keeps it in the list. So probably remove() is what you want, not destroy():

self.remove = function(item) {
    self.toDoItems.remove(item);
};

Upvotes: 2

Justin Helgerson
Justin Helgerson

Reputation: 25551

You are calling .destroy which doesn't actually remove the item from the array; it only adds a property to the object. This is intended to be a convenience for Rails developers as noted in the documentation.

If you change your code to call .remove then the item will be removed from the array.

Here is a jsFiddle as an example.

Upvotes: 1

Related Questions