2013-06-17 2 views
2

У меня есть массив объектов, хранящихся в observableArray. Каждый элемент массива является объектом date.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. Возможно, я мог бы вычислить период при добавлении элемента в массив вместо цикла?

ответ

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); 
+1

Я хотел бы добавить, что когда s оформив массив, помните, что функция 'sort' сортирует исходный массив, а не копию. Есть несколько способов сделать копию массива, но я считаю, что '[] .concat (array)' является самым быстрым. –

+0

Моя забота - это не мнение на самом деле. Я боюсь, что этот массив может стать довольно большим, и ему придется прокручивать и сортировать массив через некоторое время. Невозможно сделать это, когда элемент будет добавлен? –

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'}] 
Смежные вопросы