peanut
peanut

Reputation: 1482

Remove an item from nested observableArray

Hey I am trying to remove a item from a inner(nested) observableArray as following, but the Remove Button doesn't work (for the inner foreach items).

http://jsfiddle.net/aDahT/1871/

html:

<h4>People</h4>
<ul data-bind="foreach: peoples">
    <li>
        Name at position <span data-bind="text: $index"> </span>:
        <span data-bind="text: name"> </span>
        <a href="#" data-bind="click: $parent.removePerson">Remove</a>
        <ul data-bind="foreach:people">
             <li>
                <span data-bind="text: $data"></span>
                 <button data-bind="click: $parent.deletePerson">Remove</button>
            </li>
        </ul>
    </li>
</ul>
<button data-bind="click: addPerson">Add</button>

Script:

var Person = function(name, children){
 var self = this;
    self.name = name;
    self.people =  ko.observableArray(children);
    self.deletePerson = function() {
        alert(JSON.stringify(self));
        self.people.remove(this);
    }
}


function AppViewModel() {
    var self = this;

    self.peoples = ko.observableArray([
        new Person( 'Bert', ['baa', 'bbb'] ),
        new Person('Charles', ["caa", "cbb"] )
    ]);

    self.addPerson = function() {
        alert(this);
        self.peoples.push(new Person( "New" ,["Daa", "Dbb"] ));
    }.bind(this);

    self.removePerson = function() {

        self.peoples.remove(this);
    }
}

ko.applyBindings(new AppViewModel());

Can anyone help? Thanks first.

Upvotes: 2

Views: 1334

Answers (2)

TSV
TSV

Reputation: 7641

You can try also (jsfiddle):

<ul data-bind="foreach:people">
<li>
    <span data-bind="text: name"></span>
    <button data-bind="click: function() {$parent.people.remove($data)}, text: 'remove ' + name"></button>
</li>
</ul>

var model = {
people: ko.observableArray([{ name: "a"}, { name: "b"}, { name: "c"}])
};

ko.applyBindings(model);

Upvotes: 0

nemesv
nemesv

Reputation: 139758

Just use the first parameter of your click handler which is always set to the current view model:

self.deletePerson = function(viewModel) {
    self.people.remove(viewModel);
}

Demo JSFiddle.

Knockout also sets the this to the current viewmodel in your handlers but there is a big difference in your deletePerson and the removePerson.

In the removePerson the this is an object (your Person object) but in your deletePerson the this should be a primitive type: a string.

However Knockout uses apply to call your function and it boxes primitive types: JavaScript function call/apply with string

You check this if you log out this to the console. You will see something like:

String {0: "c", 1: "a", 2: "a", length: 3, [[PrimitiveValue]]: "caa"} 

So you will end up a boxed string in your deletePerson in the this and you need to use valueOf() (or the toString()) to get its value:

self.deletePerson = function() {
    self.people.remove(this.valueOf());
}

So just always use the first parameter provided by KO which is always the original value.

Upvotes: 2

Related Questions