Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Knockout - Using foreach and sort together

Tags:

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.

like image 688
daveywc Avatar asked Jun 03 '13 02:06

daveywc


People also ask

For what purpose do we use foreach binding in Ko?

Purpose. The foreach binding duplicates a section of markup for each entry in an array, and binds each copy of that markup to the corresponding array item. This is especially useful for rendering lists or tables.

What is Ko observable in knockout JS?

Knockout. js defines an important role when we want to detect and respond to changes on one object, we uses the observable. An observable is useful in various scenarios where we are displaying or editing multiple values and require repeated sections of the UI to appear and disappear as items are inserted and deleted.

What is $data in knockout?

The $data variable is a built-in variable used to refer to the current object being bound. In the example this is the one of the elements in the viewModel.

How do you bind data in an array?

If you want to access the array by index, you need to evaluate the observable first using () . If you want the value binding to work two-ways (i.e.: not only set it initially, but also update the values in your viewmodel after a change), you'll have to bind them to ko.


1 Answers

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" />
like image 70
nemesv Avatar answered Sep 21 '22 01:09

nemesv