正确地对backbone.js集合进行快速排序

时间:2012-03-26 02:08:09

标签: backbone.js

我可以成功地做到这一点:

App.SomeCollection = Backbone.Collection.extend({
  comparator: function( collection ){
    return( collection.get( 'lastName' ) );
  }
});

如果我想要一个仅按'lastName'排序的集合,那就太好了。但我需要动态完成这种排序。有时,我需要改为排序,比如'firstName'。

我的彻底失败包括:

我尝试将指定变量的额外变量传递给sort()。那没用。我也尝试了sortBy(),但也没有用。我尝试将自己的函数传递给sort(),但这也不起作用。将用户定义的函数传递给sortBy()只是为了使结果不具有each方法,从而无法获得新分类的主干集合。

有人能提供一个实际的例子,通过一个未硬编码到比较器函数中的变量进行排序吗?或者你有任何黑客有效吗?如果没有,请拨打sortBy()电话吗?

6 个答案:

答案 0 :(得分:37)

有趣的问题。我会在这里尝试一下策略模式的变体。您可以创建排序函数的哈希,然后根据所选的哈希成员设置comparator

App.SomeCollection = Backbone.Collection.extend({
    comparator: strategies[selectedStrategy],
    strategies: {
        firstName: function () { /* first name sorting implementation here */ }, 
        lastName: function () { /* last name sorting implementation here */ },
    },
    selectedStrategy: "firstName"
});

然后,您可以通过更新selectedStrategy属性的值来动态更改排序策略。

编辑:我在睡觉后意识到这不会像我上面写的那样工作,因为我们将对象文字传递给Collection.extend。创建对象时,comparator属性将被评估一次,因此除非被强制执行,否则它不会立即进行更改。可能有一种更简洁的方法可以做到这一点,但这证明了即时切换比较器功能:

var SomeCollection = Backbone.Collection.extend({
    comparator: function (property) {
        return selectedStrategy.apply(myModel.get(property));
    },
    strategies: {
        firstName: function (person) { return person.get("firstName"); }, 
        lastName: function (person) { return person.get("lastName"); },
    },
    changeSort: function (sortProperty) {
        this.comparator = this.strategies[sortProperty];
    },
    initialize: function () {
        this.changeSort("lastName");
        console.log(this.comparator);
        this.changeSort("firstName");
        console.log(this.comparator);        
    }                                                                                        
});

var myCollection = new SomeCollection;

这里有jsFiddle来证明这一点。

我认为,所有问题的根源都是在创建对象时立即评估JavaScript对象文字的属性,因此如果要更改属性,则必须覆盖该属性。如果您尝试将某种切换写入属性本身,它将被设置为初始值并保持在那里。

这是一个很好的blog post,它在稍微不同的背景下讨论这个问题。

答案 1 :(得分:16)

通过为其分配新功能并调用sort来更改为比较器功能。

// Following example above do in the view:

// Assign new comparator
this.collection.comparator = function( model ) {
  return model.get( 'lastname' );
}

// Resort collection
this.collection.sort();

// Sort differently
this.collection.comparator = function( model ) {
  return model.get( 'age' );
}
this.collection.sort();

答案 2 :(得分:12)

所以,这是我真正有效的解决方案。

  App.Collection = Backbone.Collection.extend({

    model:App.Model,

    initialize: function(){
      this.sortVar = 'firstName';
    },

    comparator: function( collection ){
      var that = this;
      return( collection.get( that.sortVar ) );
    }

  });

然后在视图中,我必须使用M-I-C-K-E-Y M-O-U-S-E:

this.collections.sortVar = 'lastVar'

this.collections.sort( this.comparator ).each( function(){
  // All the stuff I want to do with the sorted collection... 
});

由于Josh Earl是唯一一个尝试解决方案的人,他确实引导我朝着正确的方向前进,我接受了他的回答。谢谢Josh:)

答案 3 :(得分:4)

这是一个古老的问题,但我最近有类似的需求(根据用户点击事件提供的标准对集合进行排序)并认为我与其他人共享解决此问题的解决方案。不需要硬编码的model.get('属性')。

我基本上使用Dave Newton的approach来扩展本机JavaScript数组,并将其定制为Backbone:

MyCollection = Backbone.Collection.extend({

    // Custom sorting function.
    sortCollection : function(criteria) {

        // Set your comparator function, pass the criteria.
        this.comparator = this.criteriaComparator(criteria);
        this.sort();
    },

    criteriaComparator : function(criteria, overloadParam) {

        return function(a, b) {
            var aSortVal = a.get(criteria);
            var bSortVal = b.get(criteria);

            // Whatever your sorting criteria.
            if (aSortVal < bSortVal) {
                return -1;
            }

            if (aSortVal > bSortVal) {
                return 1;
            }

            else {
                return 0;
            }

        };
    } 

});

注意&#34; overloadParam&#34;。根据{{​​3}},Backbone使用Underscore&#34; sortBy&#34;如果你的比较器函数有一个param,如果它有两个参数,则为本机JS样式排序。我们需要后者,因此&#34; overloadParam&#34;。

答案 4 :(得分:3)

查看source code,似乎有一种简单的方法,将比较器设置为字符串而不是函数。这是有效的,给出Backbone.Collection mycollection:

        mycollection.comparator = key;
        mycollection.sort();

答案 5 :(得分:0)

这就是我最终为我正在开发的应用做的事情。在我的收藏中,我有:

comparator: function(model) {
    var methodName = applicationStateModel.get("comparatorMethod"),
        method = this[methodName];
    if (typeof(method === "function")) {
        return method.call(null, model);
    }
}

现在我可以为我的集合添加几个不同的方法:fooSort(),barSort()和bazSort()。
我希望fooSort成为默认值,所以我在我的状态模型中设置它是这样的:

var ApplicationState = Backbone.Model.extend({
    defaults: {              
        comparatorMethod: "fooSort"
    }
});

现在我要做的就是在我的视图中编写一个函数,根据用户点击的内容更新“comparatorMethod”的值。我将集合设置为侦听这些更改并执行sort(),并将视图设置为侦听排序事件并执行render()。

BAZINGA !!!!

相关问题