Question

I am using knockout/jquery-ui/knockout-sortable.

I want to drag and drop items from one sortable to another. See this plnkr for example. Try dragging one item from the first row into the second row. The underlying observable arrays are updated but the UI is inconsistent. It looks like the drag and drop is being cancelled and Knockout is not updating the UI as it should.

It works fine when the sortables are specified manually but it stops working when I create them inside a foreach binding. Anyone knows what I'm doing wrong?

The JavaScript:

  $(function() {
      viewModel = {
        firstItems : ko.observableArray(["Item 1", "Item 2", "Item 3", "Item 4"]),
        secondItems : ko.observableArray(["Item A", "Item B", "Item C", "Item D"]),
        thirdItems : ko.observableArray(["Item W", "Item X", "Item Y", "Item Z"])
      };

      viewModel.allItems = ko.observableArray([viewModel.firstItems, viewModel.secondItems, viewModel.thirdItems]);

      ko.applyBindings(viewModel);
  });

The markup:

<div id="rows" data-bind="foreach: allItems">

  <ul class="row" data-bind="sortable: $data">
    <li data-bind="text: $data"></li>
  </ul>

</div>
Was it helpful?

Solution

The sortable plugin expects to be dealing with an observableArray. In your case, based on the way that foreach works, $data is actually unwrapped to the underlying array.

Two ways that you could fix it:

  1. Use $rawData instead of $data (http://knockoutjs.com/documentation/binding-context.html) in the sortable binding to bind against the observableArray rather than its unwrapped value.

  2. Use an array of objects with a property containing the observableArray like:

    viewModel.allItems = ko.observableArray([
        { items: viewModel.firstItems }, 
        { items: viewModel.secondItems },
        { items: viewModel.thirdItems }
    ]);
    

Then, bind against items rather than $data.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top