javascript 将 jQuery UI Sortable 的顺序保存到 Backbone.js 集合
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10147969/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Saving jQuery UI Sortable's order to Backbone.js Collection
提问by VirtuosiMedia
I have a Backbone.js collection that I would like to be able to sort using jQuery UI's Sortable. Nothing fancy, I just have a list that I would like to be able to sort.
我有一个 Backbone.js 集合,我希望能够使用 jQuery UI 的 Sortable 对其进行排序。没什么特别的,我只有一个列表,我希望能够对其进行排序。
The problem is that I'm not sure how to get the current order of items after being sorted and communicate that to the collection. Sortable can serialize itself, but that won't give me the model data I need to give to the collection.
问题是我不确定如何在排序后获取项目的当前顺序并将其传达给集合。Sortable 可以序列化自身,但这不会给我需要提供给集合的模型数据。
Ideally, I'd like to be able to just get an array of the current order of the models in the collection and use the reset method for the collection, but I'm not sure how to get the current order. Please share any ideas or examples for getting an array with the current model order.
理想情况下,我希望能够获取集合中模型当前顺序的数组,并使用该集合的 reset 方法,但我不确定如何获取当前顺序。请分享使用当前模型顺序获取数组的任何想法或示例。
回答by Cymen
I've done this by using jQuery UI Sortable to trigger an event on the item view when an item is dropped. I can then trigger another event on the item view that includes the model as data which the collection view is bound to. The collection view can then be responsible for updating the sort order.
我已经通过使用 jQuery UI Sortable 在删除项目时触发项目视图上的事件来完成此操作。然后我可以在项目视图上触发另一个事件,该事件包括模型作为集合视图绑定到的数据。然后集合视图可以负责更新排序顺序。
Working example
工作示例
http://jsfiddle.net/7X4PX/260/
http://jsfiddle.net/7X4PX/260/
jQuery UI Sortable
jQuery UI 可排序
$(document).ready(function() {
$('#collection-view').sortable({
// consider using update instead of stop
stop: function(event, ui) {
ui.item.trigger('drop', ui.item.index());
}
});
});
The stopevent is bound to a function that triggers drop
on the DOM node for the item with the item's index (provided by jQuery UI) as data.
所述止挡事件被绑定到一个函数,触发器drop
,用于与项目的索引(由jQuery的用户界面提供)作为数据项的DOM节点上。
Item view
项目视图
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;
}
});
The drop event is bound to the drop
function which triggers an update-sort
event on the item view's DOM node with the data [this.model, index]
. That means we are passing the current model and it's index (from jQuery UI sortable) to whomever is bound to the update-sort
event.
drop 事件绑定到使用 data 在项目视图的 DOM 节点上drop
触发update-sort
事件的函数[this.model, index]
。这意味着我们将当前模型及其索引(来自 jQuery UI 可排序)传递给绑定到update-sort
事件的任何人。
Items (collection) view
项目(集合)视图
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();
}
});
The Items
view is bound to the update-sort
event and the function uses the data passed by the event (model and index). The model is removed from the collection, the ordinal
attribute is updated on each remaining item and the order of items by id is sent to the server to store state.
该Items
视图被绑定到update-sort
事件和功能使用由事件(模型和索引)传递的数据。从集合中删除模型,ordinal
更新每个剩余项目的属性,并将按 id 排序的项目发送到服务器以存储状态。
Collection
收藏
Application.Collection.Items = Backbone.Collection.extend({
model: Application.Model.Item,
comparator: function(model) {
return model.get('ordinal');
},
});
The collection has a comparatorfunction defined which orders the collection by ordinal
. This keeps the rendered order of items in sync as the "default order" of the collection is now by the value of the ordinal
attribute.
该集合定义了一个比较器函数,该函数按 对集合进行排序ordinal
。这使项目的呈现顺序保持同步,因为集合的“默认顺序”现在由ordinal
属性值决定。
Note there is some duplication of effort: the model doesn't need to be removed and added back to the collection if a collection has a comparator function as the jsfiddle does. Also the view may not need to re-render itself.
请注意,有一些重复的工作:如果集合具有比较器功能,则不需要删除模型并将其添加回集合,就像 jsfiddle 那样。此外,视图可能不需要重新渲染自身。
Note: compared to the other answer, my feeling was that it was more correct to notify the model instance of the item that it needed to be updated instead of the collection directly. Both approaches are valid. The other answer here goes directly to the collection instead of taking the model-first approach. Pick whichever makes more sense to you.
注意:与其他答案相比,我的感觉是通知项目的模型实例它需要更新而不是直接通知集合更正确。这两种方法都是有效的。这里的另一个答案直接指向集合,而不是采用模型优先的方法。选择对您更有意义的那个。
回答by Mateusz Godlewski
HTML:
HTML:
`<div class="test-class">
<h1>Backbone and jQuery sortable - test</h1>
<div id="items-collection-warper"></div>
</div>`
JavaScript:
JavaScript:
$(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();
});
CSS:
CSS:
.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;
}
回答by Brave Dave
Just use Backbone.CollectionView!
var collectionView = new Backbone.CollectionView( {
sortable : true,
collection : new Backbone.Collection
} );
Voila!
瞧!