Sort - drag and drop items from a list to another (copy)

I want to be able to select multiple items and copy them from a list to another (bidirectional) using drag and drop and only drop if it does not already exist ...

Some help would be appreciated a lot.

EDIT: Regarding Charlie's position and violin, how can I select multiple items to drag and drop to another list? As now, it allows only one element at a time.

HTML:

<div class="list">
    <h2>Stored procedures In DB 1</h2>
    <ul class="list" data-bind="sortable: { data: storedProceduresInDB1, beforeMove: checkAndCopy }">
        <li class="item" data-bind="text: Name"></li>
    </ul>
</div><br>

<div class="list">
    <h2>Stored procedures In DB 2</h2>
    <ul class="list" data-bind="sortable: { data: storedProceduresInDB2, beforeMove: checkAndCopy }">
        <li class="item" data-bind="text: Name"></li>
    </ul>
</div>

The code:

var ViewModel = function () {
    var self = this;
   self.storedProceduresInDB1 = ko.observableArray([
        { Name: 'SP1', Id: 1 },
        { Name: 'SP2', Id: 2 },
        { Name: 'SP3', Id: 3 }
    ]);
    self.storedProceduresInDB2 = ko.observableArray([
        { Name: 'SP3', Id: 3 },
        { Name: 'SP4', Id: 4 },
        { Name: 'SP5', Id: 5 }
    ]);
    self.selectedStoredProcedureInDB1 = ko.observable();
    self.selectedStoredProcedureInDB2 = ko.observable();
    self.selectStoredProcedureInDB1 = function (sp) {
        self.selectedStoredProcedureInDB1(sp);
    };
    self.selectStoredProcedureInDB2 = function (sp) {
        self.selectedStoredProcedureInDB2(sp);
    };
    self.checkAndCopy = function(event) {
        var targetHasItem = ko.utils.arrayFilter(event.targetParent(), function(item) {
            return item.Id == event.item.Id;
        }).length;
        if(!targetHasItem) {
            event.targetParent.splice(event.targetIndex, 0, event.item);
        }
        if(event.targetParent != event.sourceParent) {
            event.cancelDrop = true;
        }
    };
};

ko.applyBindings(new ViewModel());

Charlie jsfiddle

+4
source share
2 answers

, . , knockout.js knockout-sortable.

JSFiddle ( Chrome): http://jsfiddle.net/QWgRF/715/

HTML

, jQuery , .

options, jQuery Sortable .

.

<div class="list">
    <h2>Stored procedures In DB 1</h2>
    <ul class="list" id="sortableForDB_1" data-bind="sortable: {
      data: storedProceduresInDB1,
      beforeMove: checkAndCopy,
      options: multiSortableOptions }">
        <li class="item" data-bind="attr: { id: 'sp_'+Id }, text: Name,
          click: $root.selectProcedure.bind($data, $parent.storedProceduresInDB1()),
          css: { selected: Selected }">
        </li>
    </ul>
</div>
<div class="list">
    <h2>Stored procedures In DB 2</h2>
    <ul class="list" id="sortableForDB_2" data-bind="sortable:  {
      data: storedProceduresInDB2,
      beforeMove: checkAndCopy,
      options: multiSortableOptions }">
        <li class="item" data-bind="attr: { id: 'sp_'+Id }, text: Name,
          click: $root.selectProcedure.bind($data, $parent.storedProceduresInDB2()),
          css: { selected: Selected }">
        </li>
    </ul>
</div>

JavaScript

. 150, . 0, , .

stop observableArray, html.

helper -, .

var multiSortableOptions =  {
    delay: 150,
    revert: 0,
    stop: function(event, ui) {
        // Force lists to refresh all items
        var db1 = myViewModel.storedProceduresInDB1,
            db2 = myViewModel.storedProceduresInDB2,
            temp1 = db1(),
            temp2 = db2();
        ui.item.remove();
        db1([]);
        db1(temp1);
        db2([]);
        db2(temp2);
    },
    helper: function(event, $item) {
        // probably a better way to pass these around than in id attributes, but it works
        var dbId = $item.parent().attr('id').split('_')[1],
            itemId = $item.attr('id').split('_')[1],
            db = myViewModel['storedProceduresInDB'+dbId];

        // If you grab an unhighlighted item to drag, then deselect (unhighlight) everything else
        if(!$item.hasClass('selected')) {
            ko.utils.arrayForEach(db(), function(item) {
                if(item.Id == itemId) {
                    item.Selected(true);
                } else {
                    item.Selected(false);
                }
            });
        }

        // Create a helper object with all currently selected items
        var $selected = $item.parent().find('.selected');
        var $helper = $('<li class="helper"/>');
        $helper.append($selected.clone());
        $selected.not($item).remove();
        return $helper;
    }
};

. Selected . selectProcedure Selected ctrl + .

checkAndCopy. , , , .

var ViewModel = function () {
    var self = this;
    self.storedProceduresInDB1 = ko.observableArray([
        { Name: 'SP1', Id: 1, Selected: ko.observable(false) },
        { Name: 'SP2', Id: 2, Selected: ko.observable(false) },
        { Name: 'SP3', Id: 3, Selected: ko.observable(false) }
    ]);
    self.storedProceduresInDB2 = ko.observableArray([
        { Name: 'SP3', Id: 3, Selected: ko.observable(false) },
        { Name: 'SP4', Id: 4, Selected: ko.observable(false) },
        { Name: 'SP5', Id: 5, Selected: ko.observable(false) }
    ]);
    self.checkAndCopy = function(event) {
        var items;
        if(event.targetParent !== event.sourceParent) {
            // Get all items that don't yet exist in the target
            items = ko.utils.arrayFilter(event.sourceParent(), function(item) {
                return item.Selected() && !ko.utils.arrayFirst(event.targetParent(), function(targetItem) {
                    return targetItem.Id == item.Id;
                });
            });
            // Clone the items (otherwise the Selected observable is shared by the item in both lists)
            items = ko.utils.arrayMap(items, function(item) {
                var clone = ko.toJS(item);
                clone.Selected = ko.observable(true);

                // While we're here, let deselect the source items so it looks cleaner
                item.Selected(false);

                return clone;
            });
            // Deselect everything in the target list now so when we splice only the new items are selected
            ko.utils.arrayForEach(event.targetParent(), function(item) {
                item.Selected(false);
            });
        } else {
            // Moving items within list, grab all selected items from list
            items = event.sourceParent.remove(function(item) {
                return item.Selected();
            });
        }

        // splice items in at target index
        items = items.reverse();
        for(var i=0; i<items.length; i++) {
            event.targetParent.splice(event.targetIndex, 0, items[i]);
        }

        // always cancel drop now, since we're manually rearranging everything
        event.cancelDrop = true;
    };
    self.selectProcedure = function(array, $data, event) {
        if(!event.ctrlKey && !event.metaKey) {
            $data.Selected(true);
            ko.utils.arrayForEach(array, function(item) {
                if(item !== $data) {
                    item.Selected(false);
                }
            });
        } else {
            $data.Selected(!$data.Selected());
        }
    };

};

​​ , jQuery .

myViewModel = new ViewModel();

ko.applyBindings(myViewModel);
+2

. . . .

Ryan Niemeyer knockout-sortable (https://github.com/rniemeyer/knockout-sortable), jQuery .

knockout-sortable, beforeMove, .

JSFiddle, :

HTML

, , , beforeMove.

<div class="list">
    <h2>Stored procedures In DB 1</h2>
    <ul class="list" data-bind="sortable: { data: storedProceduresInDB1, beforeMove: checkAndCopy }">
        <li class="item" data-bind="text: Name"></li>
    </ul>
</div>
<div class="list">
    <h2>Stored procedures In DB 2</h2>
    <ul class="list" data-bind="sortable: { data: storedProceduresInDB2, beforeMove: checkAndCopy }">
        <li class="item" data-bind="text: Name"></li>
    </ul>
</div>

JavaScript

, , , , , , .

self.checkAndCopy = function(event) {
    var targetHasItem = ko.utils.arrayFilter(event.targetParent(), function(item) {
        return item.Id == event.item.Id;
    }).length;
    if(!targetHasItem) {
        event.targetParent.splice(event.targetIndex, 0, event.item);
    }
    // Only cancels drop if moving to new list to allow sorting within original list
    if(event.targetParent != event.sourceParent) {
        event.cancelDrop = true;
    }
};
+4

Source: https://habr.com/ru/post/1535549/


All Articles