Search code examples
knockout.jsknockout-2.0knockout-3.0knockout-sortableknockout-templating

Knockout nested sortable sourceParent.splice is not a function


Here I'm working on code that uses Knockout sortable. It should display nested sortables 3+ levels in depth.

The data are passed to the template, but some elements return to their original position after being dropped (e.g. A,B elements on uppermost level).

How should I configure the nested sortable so that the uppermost level can be also used without the error?

ERROR:

knockout-sortable.js:244 Uncaught TypeError: sourceParent.splice is not a function

or

knockout-sortable.js:252 Uncaught TypeError: targetParent.splice is not a function

JSFiddle - Similar working example

var viewModel = function() {
  var self = this;
  self.children = ko.observable([{
    "name": "A",
    "children": [{
      "name": "A1",
      "children": [{
        "name": "A11"
      }, {
        "name": "A12"
      }]
    }, {
      "name": "A2"
    }]
  }, {
    "name": "B",
    "children": [{
      "name": "B1"
    }, {
      "name": "B2"
    }]
  }]);
}
ko.applyBindings(new viewModel());
ul {
  border: solid 1px green;
  list-style-type: none;
  margin:0px;
}
li {
  padding: 10px;
  border: solid 1px blue;
  margin:0px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://rawgithub.com/rniemeyer/knockout-sortable/master/build/knockout-sortable.js"></script>

<script id="nodeTmpl" type="text/html">
  <li>
    <!-- ko if: $data.name -->
    <a href="#" data-bind="text: $data.name"></a>
    <!-- /ko -->
    <!-- ko if: $data.children -->
    <ul data-bind="sortable: { template: 'nodeTmpl', data: $data.children }"></ul>
    <!-- /ko -->
  </li>
</script>

<ul data-bind="sortable: { template: 'nodeTmpl', data: $root.children }"></ul>


Solution

  • The problem is solved by making changes to lines <ul data-bind="template: { name: 'nodeTmpl', data: $root }"></ul> and I removed $data from some references, because it was causing the error.

    var viewModel = function() {
        var self = this;
        self.children = [{
        "name": "A",
        "children": [{
          "name": "A1",
          "children": [{
            "name": "A11",
          }, {
            "name": "A12",
          }]
        }, {
          "name": "A2",
        }]
      }, {
        "name": "B",
        "children": [{
          "name": "B1",
        }, {
          "name": "B2",
        }]
      }]
    };
    ko.applyBindings(new viewModel());     
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/2.2.1/knockout-min.js"></script>
    <script src="https://rawgithub.com/rniemeyer/knockout-sortable/master/build/knockout-sortable.js"></script>
    
    <script id="nodeTmpl" type="text/html">
      <li>
        <!-- ko if: $data.name -->
        <a href="#" data-bind="text: name"></a>
        <!-- /ko -->
        <!-- ko if: $data.children -->
        <ul data-bind="sortable: { template: 'nodeTmpl', data: children }"></ul>
        <!-- /ko -->
      </li>
    </script>
    
    <ul data-bind="template: { name: 'nodeTmpl', data: $root }"></ul>