Knockout.js で jQuery UI ‘sortable’を使う

前回に引き続き、勉強中の Knockout の記事です。
今回は、リッチなUIを手軽に実装できる jQuery UI との組み合わせを検証してみました。

jQuery UI ‘sortable’ とは

sortable とは jQuery UI に含まれる機能で、リスト要素などの各アイテムをドラッグ&ドロップで並び替えできるようにするものです。
sortable の動きについては jQuery UI Demos & Documentation を見ていただければわかると思います。

Knockout と組み合わせる

Knockout で jQuery UI などのプラグインをバインドで実行できるようにするため、カスタムバインディングを作成します。

今回は、名前もそのまま「sortable」というカスタムバインディングを作成しました。

ko.sortable.js 4.35KB ライセンスフリー
↑右クリックして「名前をつけて保存」してください。
knockout.js の後に読み込まれるように設置すればOKです。

次のサイト・ページを参考にしました。
http://stackoverflow.com/questions/4146751/knockoutjs-with-jquery-ui-sortable
http://jsbin.com/knockoutsortable/20/edit

HTML で、通常の foreach バインディング(もしくは template バインディング)とともにバインドします。
(相応の ViewModel が適用されているものとします。)

1
2
3
<ul data-bind="foreach: List, sortable: true">
	<li data-bind="text: Text"></li>
</ul>

これだけで、リストのアイテムをドラッグ&ドロップで並び替えられるようになります。
バインドされている ViewModel のプロパティである配列「List」でも、該当するアイテムの順番が変動します。

複数のリストを扱う

jQuery UI の sortable には、単なるソートだけでなく複数のリストをまたいでアイテムを移動できるようにする機能があります。
これを実現するには、次のようにクラス名で関連付け、sortable バインディングのオプションを追加します。

1
2
3
4
5
6
<ul class="sortable" data-bind="foreach: ListA, sortable: { connectWith: '.sortable' }">
	<li data-bind="text: Text"></li>
</ul>
<ul class="sortable" data-bind="foreach: ListB, sortable: { connectWith: '.sortable' }">
	<li data-bind="text: Text"></li>
</ul>

これで2つのリスト間で、自由にアイテムをドラッグ&ドロップできるようになりました。
ドロップすると、バインドされている ViewModel のプロパティである配列「ListA, ListB」でも、該当するアイテムが移動します。
connectWith オプションは jQuery UI sortable の connectWith オプションに直接値を渡しています。
つまり、CSSのセレクタであれば問題ありません。

蛇足「ゴミ箱」

ところで、foreach バインディングを書き忘れたリストにアイテムをドロップした場合、
アイテムが追加されるべき ViewModel のプロパティが無いため、アイテムは消滅していく運命です。
というわけで、ゴミ箱オプションをつけてみました。

1
2
3
4
<ul class="sortable" data-bind="foreach: List, sortable: { connectWith: '.sortable' }">
	<li data-bind="text: Text"></li>
</ul>
<ul class="sortable" data-bind="sortable: { connectWith: '.sortable', trashBox: true }"></ul>

2つめのリストにドロップされたアイテムは、自動的に削除されます。
ゴミ箱というか、シュレッダーみたいな感じです。

sortable バインディングの各オプションについて

最後に、各オプションについて紹介します。

オプション 説明
trashBox foreach バインディングなしで、かつ trashBox オプションを true に設定した場合
接続された他のリストからこのリストにドロップされたアイテムは削除される。
また、trashBox: ‘destroy’ とすることで論理削除を行うようにすることができる。
itemAdding ほかのリストからこのリストにアイテムがドロップされる際に実行されるコールバック関数

false を返却することで、アイテムの追加(他リストからの移動)をキャンセルすることができる。

引数:

  1. item: ドロップされたアイテム(DOM要素ではなく、バインドされたアイテム)
  2. array: リストにバインドされた配列
  3. oldIndex: 移動前のリスト中でのインデックス
  4. newIndex: ドロップされたリスト中のインデックス
itemAdd ほかのリストからこのリストにアイテムがドロップされた際に実行されるコールバック関数

引数:

  1. item: ドロップされたアイテム(DOM要素ではなく、バインドされたアイテム)
  2. array: リストにバインドされた配列
  3. oldIndex: 移動前のリスト中でのインデックス
  4. newIndex: ドロップされたリスト中のインデックス
itemRemove このリストからほかのリストへアイテムがドロップされた際に実行されるコールバック関数

引数:

  1. item: ドロップされたアイテム(DOM要素ではなく、バインドされたアイテム)
  2. array: リストにバインドされた配列
  3. oldIndex: 移動前のリスト中でのインデックス
itemSort このリスト内でアイテムが並べ替えられた際に実行されるコールバック関数

引数:

  1. item: ドロップされたアイテム(DOM要素ではなく、バインドされたアイテム)
  2. array: リストにバインドされた配列
  3. oldIndex: 移動前のリスト中でのインデックス
  4. newIndex: ドロップされたリスト中のインデックス
itemDisposing trashBox オプションを true または ‘destroy’ に設定した場合、アイテムが削除される前に実行されるコールバック関数

false を返却することで、アイテムの削除をキャンセルすることができる。

引数:

  1. item: 削除されるアイテム(DOM要素ではなく、バインドされたアイテム)
itemDisposed trashBox オプションを true または ‘destroy’ に設定した場合、アイテムが削除された後に実行されるコールバック関数

引数:

  1. item: 削除されたアイテム(DOM要素ではなく、バインドされたアイテム)
jQuery UI
‘sortable’
各オプション
connectWith を含め jQuery UI の各オプションは、そのまま使用可能。
※現在、オプションに observable プロパティをバインドすることは不可能。

以上です。
そろそろちょっとしたサービスみたいなものを作ってみよう!

Posted in: Javascript, Web