如何确保敲除可观察数组仍然排序?

时间:2013-06-17 17:25:47

标签: arrays sorting knockout.js momentjs

我有一个存储在observableArray中的对象数组,每个数组项都是moment.js个日期的对象。

{startDate:momentObject, endDate:momentObject, cycle:null}

我需要计算两件事。一个是 startDates 之间的平均时间。我认为最简单的方法是计算数组中最早和最晚的startDates之间的持续时间,并将其除以条目总数。

我还需要2个startDates之间的时间段。我想出的一个快速解决方案是这样的:

$.each(dateArray, function(index, item){
    var previousItem = dateArray[index - 1];

    if(previousItem){

      // since these are moment objects, just use the diff method
      return item.cycle = previousItem.startDate.diff(item.startDate, 'days');
    }

    return false;
});

但这需要observableArray按升序排序。所以这是我的问题。

  1. 每次向其推送新项目时,如何确保observableArray 强制排序?
  2. 有没有更好的方法来计算startDates和中间期间之间的期间?
  3. 也许,我可以在向数组而不是循环添加项目的同时计算时间段吗?

3 个答案:

答案 0 :(得分:5)

您可以向obervableArray添加订阅事件处理程序,如下所示:

self.MyArray = ko.observable([]);
var myArraySubscription = self.MyArray.subscribe(onMyArrayChange);

function onMyArrayChange(){
    //Remove the subscription before sorting, to prevent an infinite loop
    myArraySubscription.dispose();
    myArraySubscription = null;

    //Force a sort of the array here. 
    self.MyArray.sort();//NOTE: You need to define your sorting logic here...this line is just a placeholder

    //Re-subscribe
    myArraySubscription = self.MyArray.subscribe(onMyArrayChange);
}

答案 1 :(得分:4)

如果您将视图数据绑定到依赖于日期数组的computed observable,则每次更新日期数组时都可以在数组上运行排序逻辑。

this.dateArray = ko.observableArray([]);

this.sortedDates = ko.computed(function() {
    var dates = this.dateArray();

    //... do sorting stuff on dates ...

    return dates;

}, this);

答案 2 :(得分:1)

使用Knockout扩展功能的另一个解决方案是:

  var unwrap = ko.utils.unwrapObservable;

  ko.extenders.sorted = function(target, key) {
    /*

    You may pass in a function, that will be used as the comparison
    function, or a key, that will be used as the attribute upon
    which we will sort.

    The value (unwrapped, if applicable) must have a valueOf() method,
    so we can compare using that.

    */

    var sortFunction;

    if (typeof key === 'function') {
      sortFunction = key;
    } else {
      sortFunction = function(a,b) {
        return unwrap(a[key]) - unwrap(b[key]);
      };
    }

    // We want to prevent our subscription firing when
    // we are already in the process of doing a sort.
    var sorting = false;

    target.subscribe(function sortSubscribe(newValue) {
      if (sorting) {
        return;
      }
      if (target().length > 1) {
        sorting = true;
        // We need to sort the observableArray, not the underlying
        // array. We could do the latter, but then would need to call
        // notifySubscribers() anyway.
        target.sort(sortFunction);
        sorting = false;
      }
    });

    return target;
  };

示例用法是:

foo = ko.observableArray([]).extend({sorted: 'key'})
foo.push({key: 'value1'})
foo.push({key: 'value0'})

foo() --> [{key: 'value0'},{key: 'value1'}]