Skip to content

Instantly share code, notes, and snippets.

@nantekkotai
Created January 23, 2013 03:45
Show Gist options
  • Save nantekkotai/4601750 to your computer and use it in GitHub Desktop.
Save nantekkotai/4601750 to your computer and use it in GitHub Desktop.
[knockoutjs]独自のイベントを追加する.その2

jQueryUIのドラッグ&ドロップに対応させる

knockout以外のライブラリやプラグインからイベントを追加することもできます。
その1で紹介したbindingHandlersに追加する方法で実装します。

※必要なjQueryUIのライブラリを読み込むこと。

// ここでドラッグ&ドロップする要素を一時的に保持します
var _dragged;

ko.bindingHandlers.draggable = {
  init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
    var dragElement = $(element),
        dragOptions = {
          // オプションの条件は各自調整
          helper: 'clone',
          revert: true,
          revertDuration: 0,
          start: function() {
            _dragged = ko.utils.unwarapObservable(valueAccessor().value);
          },
          cursor: 'default'
        };
    dragElement.draggable(dragOptions).disableSelection();
  }
};

ko.bindingsHandlers.droppable = {
  init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
    var dropElement = $(element),
        dropOptions = {
          drop: function (event, ui) {
            if (_dragged) {
              valueAccessor().value(_dragged);
              _dragged = null;
            }
          }
        };
    dropElement.droppable(dropOptions);
  }
};

var viewModel = {
  // hogehoge...
  itemList: ko.observableArray([
      { key: 'poppo', value: 'Yukio Hatoyama' },
      { key: 'kan', value: 'Naoto Kan' },
      { key: 'dojo', value: 'Noda San' }
    ]),
  dropList: ko.observableArray([]),
  addItem: function (data, event) {
    this.dropList.push(data);
  }
}
ko.applyBindings(viewModel);

大体わかるよね。
あまり美しくないやり方だと思っているけど、_draggedという変数を用意して、そこに一時的に値を保持させています。
HTML側の以下のように書きます。

<h2>Item List</h2>
<ul data-bind="foreach: itemList">
  <li data-bind="draggable: { value: $data }"><span data-bind="text: value"></span></li>
</ul>

<div data-bind="droppable: { value: addItem }">
  dropZone
</div>

<h2>Drop List</h2>
<ul data-bind="foreach: dropList">
  <li><span data-bind="text: value"></span></li>
</ul>

この例ではリストからリストに直接渡すのではなく、別のドロップゾーンにドラッグする仕様になってます。
ドロップゾーンの droppable~ という部分をDropListの方に追記すれば、直接ドロップすることもできます。

Item Listのdraggableに $data という記述がありますが、これはそのスコープのデータそのものです。
通常のJSで言うところの this です。

大体こんな感じです。

soratbleについて

ドラッグ&ドロップと言えばsortableもあるかと気になる所ですが、こっちはknockoutに対応したバージョンが既にあるので、そちらを使うと楽でしょう。

https://github.com/rniemeyer/knockout-sortable

上記ライブラリを読み込んでおけば、 foreach の代わりに sortable を使用することで簡単に並び替えを実現できます。

<h2>Drop List</h2>
<ul data-bind="sortable: dropList">
  <li><span data-bind="text: value"></span></li>
</ul>

optionを指定する方法

サクッと動くのは良いのですが、オプションの指定方法がわからなくて困りました。
指定する場合はdata-bindの一連の流れで書き込むと有効になります。

<h2>Drop List</h2>
<ul data-bind="sortable: { data:dropList, options: {axis:'y', cancel:'.key-detail'}">
  <li>
    <div data-bind="text: value"></div>
    <div class="key-detail">key: <span data-bind="text: key"></span></div>
  </li>
</ul>

optionsに必要な指定をカンマ区切りのオブジェクトで渡せば有効になります。
これは使えます。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment