Fluidbyte
Fluidbyte

Reputation: 5210

KnockoutJS cannot delete object from observableArray

I have the following code:

var testVM = {
  things: ko.observableArray([
    { id: 1, name: "Apple" },
    { id: 2, name: "Banana" },
    { id: 3, name: "Orange" },
    { id: 4, name: "Pineapple" },
    { id: 5, name: "Pear" }
    ]),

  deleteThing: function (data) {
    var things = testVM.things;
    var index = things.indexOf(data);

    // Debug...
    console.log('data', data);
    console.log('index', index);

    if (index > -1) {
        things.splice(index, 1)
    }
  },

  deleteApple: function () {
    this.deleteThing({ id: 1, name: "Apple" });
  }

};

ko.applyBindings(testVM);

With the HTML:

<ul data-bind="foreach: things">
  <li>
    <a data-bind="click: $root.deleteThing">X</a>&nbsp;|&nbsp;
    <span data-bind="text: name"></span>
  </li>
</ul>
<a data-bind="click: deleteApple">Delete Apple</a>

Which I've created in a Fiddle. The issue I'm having is that when invoked from a data-bind="click: deleteThing" inside a foreach the deleteThing function works fine, however if (in the case of the deleteApple method) I attempt to manually delete something it never finds the index and subsequently doesn't delete the item from the observableArray.

I'm stumped because in both instances the console.log shows the same data.

Upvotes: 1

Views: 61

Answers (2)

Kenneth
Kenneth

Reputation: 28737

The reason is that you try to delete an object that is not in the array:

this.deleteThing({ id: 1, name: "Apple" });

Although the values of the properties is the same, the objects are different. Objects are references and you need the correct reference, ie you need the find the index of the item and then delete at that index:

for(var i = 0;i<testVM.things.length;i++){
    if(testVM.things[i].id === 1){
        things.splice(index, 1);
    }
}

To test what I mean about references, try and execute the following code:

var x = { id: 1, name: "Apple" };
var y = { id: 1, name: "Apple" };
alert(x === y): // Alerts false

Upvotes: 2

RP Niemeyer
RP Niemeyer

Reputation: 114792

The issue that you are having is related to object references. In your deleteApple function you are passing a new object that does not match the original object reference.

The remove API does accept a function that passes the item in where you can return truthy/falsy whether you want to remove the item.

Example of using remove on an observableArray:

deleteApple: function () {
    this.things.remove(function(item) {
       return item.id === 1 && item.name === "Apple";   
    });
}

Updated fiddle: http://jsfiddle.net/rniemeyer/5HPxZ/

Upvotes: 2

Related Questions