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

Vir*_*dia 45 javascript jquery-ui backbone.js backbone.js-collections

我有一个Backbone.js集合,我希望能够使用jQuery UI的Sortable进行排序.没什么好看的,我只有一个我希望能够排序的列表.

问题是,我不确定如何在排序后获取当前的项目顺序并将其传达给集合.Sortable可以序列化自己,但这不会给我提供给集合的模型数据.

理想情况下,我希望能够只获得集合中模型的当前顺序数组,并使用重置方法进行集合,但我不知道如何获取当前顺序.请分享任何有关使用当前模型订单获取阵列的想法或示例.

Cym*_*men 81

我已经通过使用jQuery UI Sortable在项目被删除时触发项目视图上的事件来完成此操作.然后,我可以在项目视图上触发另一个事件,该事件包括模型作为集合视图绑定的数据.然后,集合视图可以负责更新排序顺序.

工作实例

http://jsfiddle.net/7X4PX/260/

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());
        }
    });
});
Run Code Online (Sandbox Code Playgroud)

所述止挡事件绑定到触发功能drop,用于与项目的索引(由jQuery的用户界面提供)作为数据项的DOM节点上.

物品视图

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;
    }
});
Run Code Online (Sandbox Code Playgroud)

drop事件绑定到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();
    }
}); 
Run Code Online (Sandbox Code Playgroud)

Items视图被绑定到update-sort事件和功能使用由事件(模型和索引)传递的数据.从集合中移除模型,ordinal在每个剩余项目上更新属性,并且按ID的项目顺序被发送到服务器以存储状态.

采集

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

该集合具有定义的比较器函数,该函数对集合进行排序ordinal.这使项目的呈现顺序保持同步,因为集合的"默认顺序"现在是ordinal属性的值.

请注意,有一些重复工作:如果集合具有比较器函数,则不需要删除模型并将其添加回集合中,如jsfiddle所做的那样.此视图也可能不需要重新渲染自身.

注意:与其他答案相比,我的感觉是,通知项目的模型实例需要更新而不是直接更新更正确.两种方法都是有效的.这里的另一个答案直接针对集合,而不是采用模型优先方法.挑选一个对你更有意义的东西.

  • 太棒了,我不知道你可以使用它的dom元素和事件哈希来触发视图上的事件.只是不思考,这很好知道! (6认同)
  • 非常棒的关于这个主题的演练.@cymen的1个简单问题 - 为什么绑定到可排序的停止事件而不是更新事件? (3认同)
  • +1我希望我能更多地投票!这是目前可用的最完整的主干示例之一(您的jsfiddle).这真的是为了显示你需要编写多少HTML才能获得一些非常酷的功能! (2认同)

小智 9

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

HTML:

`<div class="test-class">
     <h1>Backbone and jQuery sortable - test</h1>
     <div id="items-collection-warper"></div>
</div>`
Run Code Online (Sandbox Code Playgroud)

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();
});
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)


Bra*_*ave 6

只需使用Backbone.CollectionView!

var collectionView = new Backbone.CollectionView( {
  sortable : true,
  collection : new Backbone.Collection
} );
Run Code Online (Sandbox Code Playgroud)

瞧!

  • CollectionView如何使新订单持久化? (3认同)