Question

I have 2 lists which are bound to observableArrays containing the same types of objects. I want to drag an item from one list to the other list but rather than adding it as a new item I want to combine it with the item I drop it onto.

<div>
    <ul data-bind="sortable: { data: customerFields, afterMove: myDropCallback, dragged: myDraggedCallback }">
        <li><span data-bind="text: source"></span></li>
     </ul>
 </div>

 <div>
      <ul data-bind="sortable: { data: mapFields, afterMove: myDropCallback, dragged:myDraggedCallback }">
        <li><span data-bind="text: source"></span> = <span data-bind="text: destination"></span></li>
      </ul>
 </div>

The objects contain a "source" and a "destination" property, when I drag the item from the first list and drop it on an item in the second list I want to call a function that I can use to set the target items "source" property to the value of the item being dropped.

Any ideas?

Im using https://github.com/rniemeyer/knockout-sortable and it appears to have a dragged event but it doesnt look like it supports what I want to do.

Was it helpful?

Solution

knockout-sortable not only provides a sortable-binding, but also a droppable-binding. These can be used in combination to get your desired result.

Your container keeps the sortable-binding, but each item in the list also gets a droppable-binding, making them a valid target for movement.

When the droppable-binding on one of these items is triggered, you have a reference to both the item that's being moved and a reference to the item it's being moved onto.

From there you can do whatever you want, for example, you could remove the item being dragged from the parent container and merge it with the item being dragged onto.

The snippet below demonstrates the combination of sortable and draggable:

var Item = function(description) {
  var self = this;
  
  self.description = ko.observable(description);
  
  self.dropTo = function(droppedElement) {
    console.log("Drop target: " + self.description());
    console.log("Dropped element: " + droppedElement.description());
  };
};

var ViewModel = function() {
  var self = this;
  
  self.items = ko.observableArray([
    new Item("Item1"),
    new Item("Item2"),
    new Item("Item3"),
    new Item("Item4")
  ]);
  
  self.dropTo = function(arg1) {
    console.log(this);
    console.log(arg1);
  };
};

ko.applyBindings(new ViewModel());
.container {
  background-color: #999;
  padding: 4px;
}

.item {
  background-color: #ccc;
  margin: 4px;
  padding: 4px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout-sortable/1.1.0/knockout-sortable.min.js"></script>

<div class="container" data-bind="sortable: items">
  <div class="item" data-bind="text: description, droppable: { data: dropTo }"></div>
</div>

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