JQuery UIのSortableを使用してソートできるようにしたいBackbone.jsコレクションがあります。特別なことは何もありません。並べ替えできるようにしたいリストがあります。
問題は、並べ替え後にアイテムの現在の順序を取得してコレクションに伝える方法がわからないことです。 Sortableはそれ自体をシリアル化できますが、コレクションに渡す必要のあるモデルデータは得られません。
理想的には、コレクション内のモデルの現在の順序の配列を取得し、コレクションにresetメソッドを使用できるようにしたいのですが、現在の順序を取得する方法がわかりません。現在のモデルの順序で配列を取得するためのアイデアや例を共有してください。
これを行うには、jQuery UI Sortableを使用して、アイテムがドロップされたときにアイテムビューでイベントをトリガーします。次に、コレクションビューがバインドされているデータとしてモデルを含むアイテムビューで別のイベントをトリガーできます。次に、コレクションビューがソート順の更新を担当できます。
http://jsfiddle.net/7X4PX/260/
$(document).ready(function() {
$('#collection-view').sortable({
// consider using update instead of stop
stop: function(event, ui) {
ui.item.trigger('drop', ui.item.index());
}
});
});
stop イベントは、アイテムのインデックス(jQuery UIによって提供)をデータとして持つアイテムのDOMノードでdrop
をトリガーする関数にバインドされています。
Application.View.Item = Backbone.View.extend({
tagName: 'li',
className: 'item-view',
events: {
'drop' : 'drop'
},
drop: function(event, index) {
this.$el.trigger('update-sort', [this.model, index]);
},
render: function() {
$(this.el).html(this.model.get('name') + ' (' + this.model.get('id') + ')');
return this;
}
});
ドロップイベントはdrop
関数にバインドされ、データupdate-sort
を使用してアイテムビューのDOMノードで[this.model, index]
イベントをトリガーします。つまり、現在のモデルとそのインデックス(jQuery UIからソート可能)を、update-sort
イベントにバインドされているユーザーに渡します。
Application.View.Items = Backbone.View.extend({
events: {
'update-sort': 'updateSort'
},
render: function() {
this.$el.children().remove();
this.collection.each(this.appendModelView, this);
return this;
},
appendModelView: function(model) {
var el = new Application.View.Item({model: model}).render().el;
this.$el.append(el);
},
updateSort: function(event, model, position) {
this.collection.remove(model);
this.collection.each(function (model, index) {
var ordinal = index;
if (index >= position) {
ordinal += 1;
}
model.set('ordinal', ordinal);
});
model.set('ordinal', position);
this.collection.add(model, {at: position});
// to update ordinals on server:
var ids = this.collection.pluck('id');
$('#post-data').html('post ids to server: ' + ids.join(', '));
this.render();
}
});
Items
ビューはupdate-sort
イベントにバインドされ、関数はイベントによって渡されたデータ(モデルとインデックス)を使用します。モデルがコレクションから削除され、ordinal
属性が残りの各アイテムで更新され、IDによるアイテムの順序が状態を保存するためにサーバーに送信されます。
Application.Collection.Items = Backbone.Collection.extend({
model: Application.Model.Item,
comparator: function(model) {
return model.get('ordinal');
},
});
コレクションには、ordinal
でコレクションを並べ替える comparator 関数が定義されています。これにより、コレクションの「デフォルトの順序」はordinal
属性の値によるものになるため、レンダリングされたアイテムの順序が同期されます。
努力の重複があることに注意してください。jsfiddleのようにコレクションにコンパレーター機能がある場合、モデルを削除してコレクションに追加し直す必要はありません。また、ビュー自体を再レンダリングする必要がない場合もあります。
注:他の回答と比較して、更新する必要があるのではなく、更新する必要があることをアイテムのモデルインスタンスに通知する方が正しいと感じましたコレクションを直接。どちらのアプローチも有効です。ここでの他の答えは、モデルファーストアプローチをとるのではなく、直接コレクションに行きます。あなたにとってより意味のあるものを選んでください。
`<div class="test-class">
<h1>Backbone and jQuery sortable - test</h1>
<div id="items-collection-warper"></div>
</div>`
$(document).ready(function(){
var collection = [
{name: "Item ", order: 0},
{name: "Item 1", order: 1},
{name: "Item 2", order: 2},
{name: "Item 3", order: 3},
{name: "Item 4", order: 4}
];
var app = {};
app.Item = Backbone.Model.extend({});
app.Items = Backbone.Collection.extend({
model: app.Item,
comparator: 'order',
});
app.ItemView = Backbone.View.extend({
tagName: 'li',
template: _.template('<span><%= name %> - <b><%= order %></b></span>'),
initialize: function(){
},
render: function(){
var oneItem = this.$el.html(this.template(this.model.attributes));
return this;
}
});
app.AppView = Backbone.View.extend({
el: "#items-collection-warper",
tagName: 'ul',
viewItems: [],
events:{
'listupdate': 'listUpdate'
},
initialize: function(){
var that = this;
this.$el.sortable({
placeholder: "sortable-placeholder",
update: function(ev, ui){
that.listUpdate();
}
});
},
render: function(){
var that= this;
this.collection.each(function(item){
that.viewItems.Push(that.addOneItem(item));
return this;
});
},
addOneItem: function(item){
var itemView = new app.ItemView({model: item});
this.$el.append(itemView.render().el);
return itemView;
},
listUpdate: function(){
_.each(this.viewItems, function(item){
item.model.set('order', item.$el.index());
});
this.collection.sort({silent: true})
_.invoke(this.viewItems, 'remove');
this.render();
}
});
var Items = new app.Items(collection)
var appView = new app.AppView({collection: Items});
appView.render();
});
.test-class{
font-family: Arial;
}
.test-class li{
list-style:none;
height:20px;
}
.test-class h1{
font-size: 12px;
}
.ui-sortable-helper{
opacity:0.4;
}
.sortable-placeholder{
background: #ddd;
border:1px dotted #ccc;
}
Backbone.CollectionView を使用するだけです!
var collectionView = new Backbone.CollectionView( {
sortable : true,
collection : new Backbone.Collection
} );
出来上がり!