将数组与已排序的Backbone.Collection同步

时间:2014-09-23 09:55:58

标签: javascript arrays sorting backbone.js backbone.js-collections

我正在尝试将已排序的Backbone.Collection与另一个列表同步,例如一个JavaScript数组。我使用以下代码(jsfiddle):

var coll = new Backbone.Collection();
coll.comparator = "label";

var list = []

coll.on("add", function (model, collection, options) {
    list.splice(collection.indexOf(model), 0, model.get("label"));
});

coll.add([
    {label: "1"},
    {label: "3"},
    {label: "5"},
    {label: "4"},
    {label: "2"}
]);

在此示例中,这会产生以下列表:1, 2, 3, 5, 4。根本原因是,在add事件处理程序中,Backbone.Collection已经填充了所有模型,而JS数组则没有。由于添加事件是按插入顺序触发的,而不是按排序顺序触发,因此会导致数组中的顺序错误。

如何更改同步方法/添加处理程序以使其有效?

2 个答案:

答案 0 :(得分:0)

听起来您在初始化期间发生了错误:

var coll = new Backbone.Collection([
    {label: "1"},
    {label: "3"},
    {label: "5"},
    {label: "4"},
    {label: "2"}
], { comparator: 'label' )

var list = coll.pluck('label')

// Assuming your add-handler works, you can keep that around for future add's
coll.on("add", function (model, collection, options) {
    list.splice(collection.indexOf(model), 0, model.get("label"));
});

如果这还不够,那么您需要做一些涉及sync事件的add事件的工作。不过,我建议您li的观点只听取coll,然后在coll触发addremove时完全重新呈现},或sort。这将完全阻止尝试保持两个阵列彼此同步,这在编程中是禁止的。通常,您将创建一个数据结构来处理该交互,但您的集合应该足够了:

var LabelsView = Backbone.Collection.extend({
    el: '#my-list',
    template: '<% coll.each(function(model){ %> <li><%- model.get("label") %></li><% }); %>',
    initialize: function(){
        this.listenTo(this.collection, 'add remove sort', this.render)
    }
    render: function(){
        this.$el.html( this.template({ coll: this.collection }) )
    }
}) 

var labelView = new LabelsView({ collection: coll })

答案 1 :(得分:0)

首先,您需要收听sort事件

    this.listenTo(this.collection, 'sort', this.sortList);

然后将data-id标识符添加到每个列表项

    var li = $("<li>", { "data-id": model.get("label") }).html(model.get("label"));

然后根据不相等的位置对html项目进行排序

    sortList: function(collection, options) {
        collection.forEach(function(model, index) {
            var li1 = this.$el.children().eq(index),
                li2;
            if (model.get("label") != li1.data("id")) {
                li2 = this.$el.children("[data-id=" + model.get("label") + "]");
                li1.before(li2);
            }
        }, this);
    },

jsfiddle link http://jsfiddle.net/n0fdmb8a/3/