Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Knockout - Deleting item from ViewModel doesn't remove from DOM

Tags:

knockout.js

I have a view model which contains a collection of objects, 'Files'.

Obviously this is bound to the DOM.

When I remove an item from the 'Files' collection I would expect the DOM to be updated to reflect this, but it doesn't update.

This is the JS that I use for removing an item from the 'Files' collection.

this.Delete = function(id) {
    for (var f = 0; f < this.Files.length; f++) {
        if (this.Files[f].ID() == id) {
            this.Files.splice(f, 1);
        }
    }
}.bind(this);

If I print the length of the collection to the console after calling Delete(id), I can see that an item has been removed.

So why does the DOM not update?

If I call ko.applyBindings(... then it does update, but my understanding is that I shouldn't have to call this every time the view model updates.

So what might I be doing wrong?

Also, I've tried it with Files as an observableArray and a standard array, without any difference.

UPDATE: here's the definition of the view model (well... the relevant part, anyway)

function Files(files) {

    var self = this;

    self.Files = ko.observableArray([]);

    this.Delete = function(id) {
        // find which index the specified ID exists at
        for (var f = 0; f < this.Files().length; f++) {
            if (this.Files()[f].ID() == id) {
                this.Files().splice(f, 1);
            }
        }
    }.bind(this);

    ...
}

I've also tried it with

self.Files = [];

and then changing every instance of Files() to just Files. No difference.

like image 890
awj Avatar asked Apr 30 '13 15:04

awj


1 Answers

You need to have the observable array:

self.Files = ko.observableArray([]);

but you need to call splice directly on the observable array with this.Files.splice:

this.Delete = function(id) {
    // find which index the specified ID exists at
    for (var f = 0; f < this.Files().length; f++) {
        if (this.Files()[f].ID() == id) {
            this.Files.splice(f, 1);
        }
    }
}.bind(this);

otherwise you remove the item form the underlying array without KO knowing about the removal so it cannot update the DOM. See also the documenation Manipulating an observableArray section.

By the way the observableArray has a remove function which could greatly simplify your code:

this.Delete = function(id) {
    this.Files.remove(function(item) { return item.ID() == id; } );        
}.bind(this);
like image 68
nemesv Avatar answered Oct 25 '22 03:10

nemesv