Knockout - Using foreach and sort together

14,502

The observableArray.sort returns the sorted underlying ("regular") array and not a observableArray that is why the changes not shown on the UI.

To have the sorting and the UI updated you need to create a ko.computed which does the sorting and use the computed in your binding. Because the ko.computed will listen on the widgets changes and recalculate the sorting.

var widgets= ko.observableArray();

var sortedWidgets = ko.computed(function() {
   return widgets().sort(function (left, right) { 
        return left.order() == right.order() ? 
             0 : 
             (left.order() < right.order() ? -1 : 1); 
   });
});

Then you can bind it with:

<article data-bind="foreach: sortedWidgets" />
Share:
14,502

Related videos on Youtube

rbrtl
Author by

rbrtl

Experienced software anaylyst/developer running a small team developing mainly web based and mobile software. Main technologies used are C#, Objective C, Java, MS SQL Server, Visual Studio, ASP.Net MVC, JQuery, Javascript, WPF, WCF, breezejs, durandal and angularjs

Updated on June 19, 2020

Comments

  • rbrtl
    rbrtl about 4 years

    I am having trouble combining the foreach binding with a sort. I have a list bound like so:

    <article data-bind="foreach: widgets">  
    

    Widgets is a simple obvservable array:

    var widgets= ko.observableArray();
    

    This works nicely giving me a list of my "widgets". If I add a new "widget" to this list then it appears dynamically in the list via data binding.

    However as soon as I add sorting to the array:

    <article data-bind="foreach: widgets.sort(function (left, right) { return left.order() == right.order() ? 0 : (left.order() < right.order() ? -1 : 1); })">
    

    Then newly added widgets no longer appear in my list - unless I reload the page. (The sorting works nicely at this point - if I update the "order" field that I am sorting on then the items in my list are dynamically re-sorted).

    How can I go about getting the sorting to play nicely with the dynamic updating of new items in my observable array?

    I am using Breezejs in order to retrieve my data, however I do not think that is impacting on this scenario.

  • rbrtl
    rbrtl about 11 years
    Thank- you - that worked nicely. Can you please update your answer to include "function () " at the start of the ko.computed (inside the first parentheses). I will then accept it as the answer.
  • rbrtl
    rbrtl about 11 years
    Further to your answer above, how do I then make this work for a nested foreach i.e. a foreach on a navigation property of one of the widgets in my top level list. In this case I do not explicitly declare the observable array that I am binding to so I cannot see how to use this approach.
  • nemesv
    nemesv about 11 years
    I've fixed the typo in my answer. I'm not familiar with Breezejs but I think it can be configured to create these custom sorted properties for you. Anyway JS is dynamic so you can add new properties to any already existing object.
  • rbrtl
    rbrtl about 11 years
    I was able to get the sorting to work on the nested foreach for the navigation properties by adding a knockout computed property to my Breeze entity in a custom constructor - see breezejs.com/documentation/extending-entities.
  • PW Kad
    PW Kad about 11 years
    @daveywc Could you post an example of how you were able to that while using sort?