Search code examples
functionknockout.jsko.observablearray

knockout issue with deleting from observable array


I'm having data binding a knockout function to my html.

Following is the view model:

  var DonutViewModel = function () {
        this.donuts = ko.observableArray();
        //donutData = JSON.parse(donutData);
        var items = $.map(donutData, function (data) { return new Donut(data) });
        this.donuts(items);
        this.deletedonut = function (item) {
            this.donuts.remove(item);
        }
    }
   var viewModel;
   $(document).ready(function () {
      viewModel = new DonutViewModel();
      ko.applyBindings(viewModel);
   });

following is the html:

 <tr>
    <td><input id="txtdonutid" type="text" data-bind="value:id"/></td>
    <td><input id="txtdonuttype" type="text" data-bind="value:type"/></td>
    <td><input id="txtdonutname" type="text" data-bind="value:dname"/></td>
    <td><input id="txtppu" type="text" data-bind="value:ppu"/></td>
    <td><input type="button" value="Delete Donut" data-bind="click: function() {$parent.deletedonut($data)}"/></td>
</tr>

Notice how I have data-bound the delete function and THIS WORKS!. but if I do the following:

  <td><input type="button" value="Delete Donut" data-bind="click: {$parent.deletedonut($data)}"/></td>

well, this doesn't work. The delete function doesn't even get hit.

Can someone tell me what I'm doing wrong?


Solution

  • You only need to the function() ... syntax in your click binding if you want to pass additional parameter to your handler beside the $data. (see the documentation: Accessing the event object, or passing more parameters section)

    But if your only parameter is $data then KO will automatically pass that in so you can just write:

    <input type="button" value="Delete Donut" 
                         data-bind="click: $parent.deletedonut"/>
    

    Note: there is no need for the {} and you also don't need arguments as well ($data) because you are passing the $parent.deletedonut as the reference to that handler function.

    But in itself this won't work in your case because you are using this in your handler to access your view model.

    You have two options:

    You can use bind: data-bind="click: $parent.deletedonut.bind($parent)" in this case you don't need to change your handler.

    Demo JSFiddle

    Or you can store a reference of the this in a variable like self and use that in your handler instead of the this.

    So change your handler to:

    var self = this; 
    this.deletedonut = function (item) {
        self.donuts.remove(item);
    } 
    

    Demo JSFiddle.