I am working on a simple Web App, where Users can comment articles chronologically (like comments on an blog article). Every comment has a timestamp. I use KnockoutJS for a client side view model and due to problems with the date object in IE9 I use MomentJS for crossbrowser timestamp parsing (the Timestamp Property of every comment is in fact a MomentJS generated object). Data comes from an REST Endpoint as JSON to the client where it is instantiated in the Knockout view model. The constructor of my article model looks like this (shortened):
GC.ko.modelArticle = function (a) {
this.Id = ko.observable(a.Id);
this.Title = ko.observable(a.Title).extend({ required: true, minLength: 3 });
: //some more Properties
this.Comments = ko.observableArray();
if (util.isDefined(a.Comments)) {
for (var i = 0; i < a.Comments.length; i++) {
this.Comments.push(new GC.ko.modelComment(a.Comments[i]));
}
}
this.Comments.sort(function (left, right) {
return left.Timestamp == right.Timestamp ? 0 : (left.Timestamp < right.Timestamp ? -1 : 1);
});
};
As you can see, if the JSON (a) contains comments, these are pushed onto a Knockout observableArray. Afterwards I am sorting the Array chronologically ascending, so that newer Comments appear after older ones in the UI.
In Firefox and Chrome the array gets sorted ascending, as it should.
In IE9 it is sorted descending.
Does this happen because of
- crossbrowser issues of the Array().push() function
- or the Array().sort() function,
- or because Knockout observable Arrays have issues with sorting,
- or is it because of some error in my code?
EDIT: comment.Timestamp is an Knockout Observable. I tried two variants:
First returning a plain Javascript Date Object (which had Timestamp parsing issues in IE, so I had to modify this):
this.Timestamp = ko.observable(c.Timestamp)
Second returning a moment Object:
this.Timestamp = ko.observable(moment(c.Timstamp)
- 'c' is the JSON for a comment
EDIT 2: It turns out, that the sort() function of observableArray() in Knockout 2.2.1 seems to be the problem. I modified my code to the following (first sorting the plain javascript array, then pushing the elements to the KO Observable Array) and everything works as it should now. Here's the code:
GC.ko.modelArticle = function (a) {
this.Id = ko.observable(a.Id);
this.Title = ko.observable(a.Title).extend({ required: true, minLength: 3 });
: //some more Properties
this.Comments = ko.observableArray();
if (util.isDefined(a.Comments)) {
a.Comments.sort(function(left,right) {
return left.Timestamp == right.Timestamp ? 0 : (left.Timestamp < right.Timestamp ? -1 : 1);
});
for (var i = 0; i < a.Comments.length; i++) {
this.Comments.push(new GC.ko.modelComment(a.Comments[i]));
}
}
};
return +right.Timestamp - left.Timestamp