Question

Background

To learn Knockout JS, I'm (slowly) building a gradebook in the browser. My lastest issue involves dropping the lowest scores in an observable array. I have a student model, which has an observable array called scores. This array consists of observable scores, which are plain numbers.

My methodology for removing the lowest grades is as follows. First, I sort each array of scores, high-low, then, for now, splice the end of the array, such that the two lowest numbers are stored into a new array called low. The low variable will be used later when I calculate the mean.

The Problem(s)

First, my current dropLowestGrades method outright removes data from the dom, which I do not desire. Second, myObservableArray.sort() does not appear to do any sorting! I'm not sure where to go here. Relevant script follows.

JSBin: http://jsbin.com/fehoq/141/edit

JS

var StudentsViewModel = (function () {
    function StudentsViewModel() {
        var _this = this;

        ...

        this.dropLowestScores = function() {
            var low = [];
            ko.utils.arrayForEach(_this.students(), function(student){
                console.log(student.fullName());
                student.scores().sort();
/*                        
                student.scores().sort(function(a, b) { 
                  return a() == b() ? 0 : (a() > b() ? 1 : -1);
              });
*/                      
              low = student.scores.splice((student.scores().length-2),student.scores().length);
              console.log('low: ' + low);
              return low;
            });
        }; 

HTML

I currently just bind the function to a button. For simplicity's sake, I'm hard-coding the drop to be two scores. I will later allow the user to pass in a value. Note that the button is named "Sort" right now because I was originally going to have a sort feature, then build my dropLowestScores method on top it.

  <button data-bind="click: dropLowestScores">Sort</button>

Update

I have significantly updated my method after insights from the answers. The script below still suffers from cutting the values in my scores array, which I do not wish to change.

this.dropLowestScores = function() {
    ko.utils.arrayForEach(_this.students(), function(student){
        console.log(student.fullName());
        var tmp = student.scores().sort();
        console.log(tmp);
        student.lowest = tmp.splice((tmp.length-2),tmp.length);
        console.log('student lowest: ' + student.lowest);
    });
};

Update 2

I changed my StudentModel such that it now has property lowest, which keeps track of the lowest scores when user drops grades.

var StudentModel = (function () {
    function StudentModel(fullName) {
        var _this = this;
        this.fullName = ko.observable(fullName);
        this.scores = ko.observableArray();
        this.lowest = [];
        ...
Was it helpful?

Solution

You need to remember that functions like sort() return a sorted list of the array, they don't actually transform the array itself.

var studentScores = student.scores().sort();

or something like -

var sortedStudentScores(function () {
    return student.scores().sort();
});

And if you are sorting on a property of the score you need to use something like -

var sortFunction = // Google a JavaScript sort function
var studentScores = student.scores().sort(sortFunction);

and if you are trying to remove items splicing is correct (it transforms the array itself) otherwise you need to use something like a computed to just not add the lowest in.

Updated

var sortedStudentScores(function () {
    // Set a local var equal to the sorted scores
    var theseScores = student.scores().sort().splice(0);
    theseScores.splice(student.scores().length-2),student.scores().length);
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top