简体   繁体   English

将jQuery UI Sortable的顺序保存到Backbone.js集合中

[英]Saving jQuery UI Sortable's order to Backbone.js Collection

I have a Backbone.js collection that I would like to be able to sort using jQuery UI's Sortable. 我有一个Backbone.js集合,我希望能够使用jQuery UI的Sortable进行排序。 Nothing fancy, I just have a list that I would like to be able to sort. 没什么好看的,我只有一个我希望能够排序的列表。

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. 请分享任何有关使用当前模型订单获取阵列的想法或示例。

I've done this by using jQuery UI Sortable to trigger an event on the item view when an item is dropped. 我已经通过使用jQuery UI Sortable在项目被删除时触发项目视图上的事件来完成此操作。 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. 然后,集合视图可以负责更新排序顺序。

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 stop event 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] . drop事件绑定到drop函数,该函数在项目视图的DOM节点上使用数据[this.model, index]触发update-sort事件。 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. 这意味着我们将当前模型及其索引(从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). Items视图绑定到update-sort事件,函数使用事件传递的数据(模型和索引)。 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. 从集合中移除模型,在每个剩余项目上更新ordinal属性,并将按项目的顺序发送到服务器以存储状态。

Collection 采集

Application.Collection.Items = Backbone.Collection.extend({
    model: Application.Model.Item,
    comparator: function(model) {
        return model.get('ordinal');
    },
});

The collection has a comparator function defined which orders the collection by ordinal . 该集合具有定义的比较器函数,该函数按顺序对集合进行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属性的值。

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. 请注意,有一些重复工作:如果集合具有比较器函数,则不需要删除模型并将其添加回集合中,如jsfiddle所做的那样。 Also the view may not need to re-render itself. 此视图也可能不需要重新渲染自身。

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. 挑选一个对你更有意义的东西。

http://jsfiddle.net/aJjW6/2/ http://jsfiddle.net/aJjW6/2/

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;
}

Just use Backbone.CollectionView ! 只需使用Backbone.CollectionView

var collectionView = new Backbone.CollectionView( {
  sortable : true,
  collection : new Backbone.Collection
} );

Voila! 瞧!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM