Observable array of draggable items and dropping values onto sortable list items

1.4k views Asked by At

I've been playing with Ryan Niemeyer's excellent knockout-sortable plugin and the draggable example in particular.

I'm looking to achieve two things:

  1. Create an observable array of draggable items.
  2. Rather than drag items into the sortable list, I want to drop dragged items onto items in the sortable list and replace their value.

In the below fiddle, I've begun the first objective but the Text: name binding doesn't work. I'd appreciate any guidance with this and the second objective.

http://jsfiddle.net/AC49j/125/

1

There are 1 answers

5
Hans Roerdinkholder On

I'm not entirely sure what your issues with the code are, works pretty well already :). I do think I see what your problem is with the text: name binding, I think the change below fixes it the way you want it:

<div id="draglist" data-bind="foreach: newTask">
    <div class="item" data-bind="draggable: $data"> // Changed from data-bind="draggable: name()"
        <span data-bind="text: name"></span>
    </div>
</div>

$data in this case represents the whole task, while name() represents the ACTUAL (string) VALUE of the observable name-attribute of the task. It seems this change makes it function the way you want it to.

The second objective is less clear to me. Which items should be droppable onto which items? E.g. should items from the right container be droppable on items of the left container? Or should everything be able to drop on/replace everything else? What about sort, is that even still needed?

jQuery droppable custom binding (in response to comments below)

    ko.bindingHandlers.droppable = {
        init: function (element, valueAccessor) {
            var $element = $(element),
                options = ko.unwrap(valueAccessor());

            $element.droppable(options.settings);

            if (!options.enable) {
                $element.droppable('disable');
            }

            // Handle disposal
            ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
                $element.droppable('destroy');
                $element = null;
            });
        },
        update: function (element, valueAccessor) {
            var $element = $(element),
                options = ko.unwrap(valueAccessor()),
                action = options.enable ? 'enable' : 'disable';

            $element.droppable(action);
        }
    };

To use it:

// HTML
<div data-bind="droppable: { settings: droppableSettings, enable: canDrop }"></div>

// JS (viewmodel)
var droppableSettings = {
    drop: function (event, ui) {
        var dropTarget = ko.dataFor(this);
        // perform your replace logic
    },
    hoverClass: 'container-hover',
    over: function () {
        // Handle over-event from jQuery droppable
    },
    tolerance: 'pointer'
    // For more settings, see http://api.jqueryui.com/droppable/
},
canDrop = ko.observable(true);