Search code examples
knockout.jsknockout-mapping-plugin

Knockout: click binding to add/remove item in hierarchy


I would like to understand how to call add/delete functions from within a knockout hierarchy. For example, if I am inside nested foreach, and I click on a delete button, how can I call a function that will let me delete the item (and do some other things too)?

Here's a Fiddle of the problem. https://jsfiddle.net/4a3z4urc/

In the html, the commented-out button works, but I need the function to be inside my script tags (which isn't working).

function ViewModel(data){
    var self = this;
    self.pages = ko.mapping.fromJS( data );
    self.OutputJson = function(){
        console.log(ko.toJSON(self));
    }

    self.removePage = function(pageName) { self.pages.remove(pageName) };
    self.removeRow = function(rowType) { self.pages.pageRows.remove(rowType) };
    self.removeSlide = function(slide) { self.slides.remove(slide)  };
    self.addSlide = function(slide) {}
}

How can I make the RemoveRow and RemoveSlide functions delete the correct item? (Json is shown below the demo). Thanks!


Solution

  • Your problem is that in your "inner" remove method you don't have the information of the "currently selected" page, pageRow, slide, etc.

    One solution would be to pass in the current $parent into your click handlers:

    <div data-bind="foreach: pageRows">
        <section style="border:1px solid pink; padding:5px;">
    
          <button type="submit" data-bind="click: $root.removeRow.bind($parent, $data)" 
              class="btn-delete"><i>&times;</i></button>
    
         ...
       </section>
    </div>
    

    And now you can access the "currently selected" page with this in your handler:

    self.removeRow = function(rowType) { this.pageRows.remove(rowType) };
    

    Demo JSFiddle.

    Note that you also need to use $root to access the "top level" if you inside are multiple foreach bindings.

    You can also pass in the $parent as a paramter: root.removeRow.bind(null, $parent, $data), and in this case your handle would look like this:

    self.removeRow = function(page, rowType) { page.pageRows.remove(rowType) };
    

    You can read more about the different additional paramter passing options in the documentation.