【问题标题】:How to render a sorted collection from unsorted data in Backbone?如何从 Backbone 中的未排序数据呈现排序集合?
【发布时间】:2014-09-07 11:27:01
【问题描述】:

我正在从服务器获取未排序的数据,并希望使用 Backbone 将其显示在排序列表中。为此,我在集合中使用了comparator。但是,当一次将多个模型添加到集合中时,Backbone 会以不方便的顺序触发 add 事件。

这是一个说明我的问题的示例(JSFiddle:http://jsfiddle.net/5wtnjj8j/2/):

PersonCollectionViewinitialize 函数中,我将三个人添加到集合中(请注意,他们没有正确排序)。每次 Backbone 将其中一个模型插入到集合中时,它都会触发 add 事件并调用我的 personAdded 函数。这个函数输出插入的人的名字和插入的索引。

这是我得到的输出:

insert "Alice" at index: 0
insert "Eve" at index: 2
insert "Bob" at index: 1

显然,索引是正确的(即按名称排序)。 但是为什么 Backbone 会按照指定模型的顺序而不是索引的顺序触发add事件?

我认为这种行为是违反直觉的,因为它使构建视图的排序列表变得困难。例如,假设我想为模型构建一个<ul>。插入 Alice 会起作用(因为她的索引为 0),但是当第二个 add 事件到达时,我将在索引 2 处插入 Eve,而没有先在索引 1 处收到 Bob。

Backbone 以“错误”顺序触发add事件有什么特殊原因吗?有没有办法接收按索引排序的事件?


型号

var Person = Backbone.Model.extend({
    defaults: {
        name: 'Unknown'
    }
});

收藏

var PersonCollection = Backbone.Collection.extend({
    model: Person,
    comparator: 'name'
});

查看

var PersonCollectionView = Backbone.View.extend({
    initialize: function() {
        this.collection = new PersonCollection();
        this.collection.on('add', this.personAdded, this);

        var models = [{name: 'Alice'}, {name: 'Eve'}, {name: 'Bob'}];
        this.collection.add(models);
    },

    personAdded: function(model, collection, options) {
        var index = collection.indexOf(model);
        var message = 'insert "' + model.get('name') + '" at index: ' + index + '<br>';

        $('body').append(message);
    }
});

【问题讨论】:

    标签: sorting backbone.js


    【解决方案1】:

    解决您的问题的一个简单方法是在将模型列表添加到集合之前对其进行排序。

    var models = [{name: 'Alice'}, {name: 'Eve'}, {name: 'Bob'}];
    this.collection.add(_.sortBy(models, 'name'));
    

    这是一个例子http://jsfiddle.net

    Backbone 正在按照您给它们的顺序添加模型,然后对它们进行排序,在第一个事件到达您的 personAdded 函数之前,Backbone 已经添加了所有模型,这就是您为 Eve 获得索引 2 的原因而不是 1


    对于fetch调用,尝试重新定义parse函数:

    var PersonCollectionView = Backbone.View.extend({
      ...
      parse: function(response) {
        return _.sortBy(response, 'name')
      }
    

    【讨论】:

    • 谢谢,这适用于我的示例。但是,当我使用 fetch 从服务器获取模型时,在将它们插入集合之前,我没有机会使用下划线对它们进行排序。
    • 当您从服务器获取模型时,没有添加事件(但 sync 事件),并且在添加所有模型后集合会自行排序,那么您的问题在哪里?
    • 我刚刚再次检查:在集合上调用 fetch 会为收到的每个模型触发一个 add 事件,并在添加所有模型后触发一个 sync 事件。问题和之前一模一样:模型的索引是排序的,但是add事件的触发顺序错误(即服务器发送模型的顺序)。
    【解决方案2】:

    相信你也可以新建一个集合,用未排序的数组实例化这个集合

    initialize: function() {
    
            var models = [{name: 'Alice'}, {name: 'Eve'}, {name: 'Bob'}];
            this.collection = new PersonCollection(models );
    
            this.collection.on('add', this.personAdded, this);
        },
    

    您可以采取的另一种方法是在添加项目后声明您的集合添加绑定。

       initialize: function() {
            this.collection = new PersonCollection();
    
            var models = [{name: 'Alice'}, {name: 'Eve'}, {name: 'Bob'}];
            this.collection.add(models);
    
            this.collection.on('add', this.personAdded, this);
        },
    

    Edit:创建集合视图的替代方法。让视图知道容器在哪里/是什么(在这种情况下是主体)通常不是一个好主意。从 render() 函数返回视图内容是一种更好的做法。然后将视图的el添加到body中。

    var PersonCollectionView = Backbone.View.extend({
        initialize: function(opts) {        
            var models = [{name: 'Alice', index:1}, {name: 'Eve', index:2}, {name: 'Bob', index:3}];
    
            this.collection = new PersonCollection(models);
            this.collection.on('add', this.personAdded, this);
        },
        personAdded: function(model, collection, options) {
            var index = collection.indexOf(model);
            var message = 'insert "' + model.get('name') + '" at index: ' + model.get('index') + '<br>';
    
            this.$el.append(message);
        },
        render: function(){
            this.collection.each(function(model){
                this.$el.append('insert "' + model.get('name') + '" at index: ' + model.get('index')+"</br>");
            },this);
            return this;    //making it chainable (render().$el);
        }
    });
    
    //from server
    var personCollectionView = new PersonCollectionView();
    
    $('body').append(personCollectionView.render().el);
    

    【讨论】:

    • 在这两种情况下,由于缺少 add 事件,视图都不会呈现。但我想这可以手动完成......
    • 感谢您的编辑。在我的示例中,我只是将输出直接添加到正文中以使其简单。在实际应用程序中,我为每个人创建了一个视图。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-08
    • 2014-08-30
    • 1970-01-01
    • 1970-01-01
    • 2020-11-17
    相关资源
    最近更新 更多