Search code examples
javascripthtmlknockout.jsko.observablearray

Knockout JS: Value passed to Writeable Computed returns [object Object]?


Background

While working on an ongoing learning project, I noticed that I require a writeable computed function to solve a problem I'm facing. Here's the skinny: I'm trying to 1) drop a user-specified number of assignments scores 2) of a user specified type from a gradebook.

The user inputs the value above, then click a button, dropLowestScores. The code then adds the lowest scores to an array called 'lowest', which exists on each student object. Then, observable means on each student are updated based on new values, dropping the lowest ones.

Problem

My problem comes to life when I try to drop. I'm not confident that my writeable computed is structured correctly, but I'm not sure what's wrong either. I noticed that that properties 'n' and workType are correctly given in my read function, but in my write, they are not as desired. In read, for example, workType returns default value, homework, but in my write function, it returns [object Object].

Responses that can clarify what my problem is and give me a strategy for correctly scripting a writeable computed would be appreciated.

Relevant JS and HTML snippets follow.

JSBin: Full Project

JS

this.dropLowestScores = ko.computed({

    // read the parameters necessary to write values to property 'lowest'

    read: function() {

        // user sets value of 'n' in the page via ko 'options'

        var n = _this.n().n;

        // user selects 'workType' from list of ko options            

        var workType = _this.workType().workType;
        console.log("workType:" + workType);
        return n,workType;   
    },

    // now use current parameter values to set new values to 'lowest' arrays 

    write: function(n,workType) {
        //this.n = n;
        //this.workType = workType;

        // 'lowest' exists as a property for each student, 
        // ergo, I loop through each student 

        ko.utils.arrayForEach(_this.students(), function(student){
            var i = _this.students.indexOf(student);

            console.log("_this.assignments: " + _this.assignments()[i].workType().workType);
            console.log("this.workType: " + this.workType);
            console.log(_this.assignments()[i].workType().workType == this.workType);

            // if the current assignment is the same as the user-specified assignment, 
            //add the score for that assignment to array 'tmp'; then set lowest = tmp 

            if(_this.assignments()[i].workType().workType == this.workType){
                var tmp = student.scores().sort(_this.comparator).slice(0,this.n);
                console.log(tmp.length);
                student.lowest(tmp);
            }    
        });
    }
});     

HTML

<button data-bind="click: dropLowestScores">Drop Lowest Scores</button>

Currently, I just have the above function bound to a butten. Ideally, this is how I'd leave it. Other properties referenced, such as n, workType, and mean are input in a table.


Solution

  • I feel silly now, but it turns out I was on the right track; indeed, the solution was trivially simple. In the read function, I just needed to define properties in the following way:this.variable = ... as opposed to var variable = ....

    this.dropLowestScores = ko.computed({
    
        // read the parameters necessary to write values to property 'lowest'
    
        read: function() {
    
            // user sets value of 'n' in the page via ko 'options'
    
            this.n = _this.n().n;
    
            // user selects 'workType' from list of ko options            
    
            this.workType = _this.workType().workType;
    
            console.log("workType:" + workType);
            return n,workType;   
        },
    
        ...