Pregunta

Background

I have a plain JS array, initially empty. I later populate it with values. The values sent to it are numbers that are Knockout observables. Later, I want to compare those values to values in another, knockout observable array. My problem is that whenever I pass the index of the current item in my array loop, and pass that index value (a number!), the array returns a function. To get an idea, look at the JS that follows.

Note that my project and actual script is viewable on JSBin. Further, to view the problem in the console, you have to add assignments, then press 'sort'.

JSBin: http://jsbin.com/fehoq/177/edit]1

JS

//example script that follows actual script

var _this = this;

//initialize my array
this. lowest = [];

// I want to compare values in lowest to values in this array
this.scores = ko.observableArray();

// method that does comparison
this.myMethod = function(){

    // initialize my helper, k
    var k;  
     ...

    // loop through one array
    ko.utils.arrayForEach(_this.scores(), function (score) {

        // make sure my value is a number...
        if (!isNaN(parseFloat(score()))) {

           // this is important, I need to current index for comparison
           k = _this.scores.indexOf(score);
           console.log(k);

           // this is where things break - it prints a function, not a value!
           console.log(_this.lowest[k]);

           // useless check, the value is a function, so they're always different
           if (score()!=_this.lowest[k]){
             // do stuff
           }
        }
    }
}

Update

Putting the method I'm using, maybe someone will notice something I missed given that my syntax is correct(?).

this.mean = (function(scores,i) {
  var m = 0;
  var count = 0;
  var k;

  ko.utils.arrayForEach(_this.scores(), function(score) {

    console.log([typeof score(), score()]);

    if (!isNaN(parseFloat(score()))) {

      console.log(i);
      console.log(_this.lowest[i]);

      if (score() != _this.lowest[i]) {
        m += parseFloat(score());
        count += 1;
      }

    }

  });

 if (count) {
    m = m / count;
    return m.toFixed(2);
  } else {
    return 'N/A';
  }
});
}

Update 2

Just in case someone else wanders over here since my problem isn't solve still. The following code is how I set the value of lowest:

this.dropLowestScores = function() {
    ko.utils.arrayForEach(_this.students(), function(student){
        var comparator = function(a,b){
          if(a()<b()){
            return 1;
          } else if(a() > b()){
            return -1;
          } else {
            return 0;
          }
        };       
        var tmp = student.scores().slice(0);
        tmp.sort(comparator);
        student.lowest = ko.observableArray(tmp.splice((tmp.length-2),tmp.length-1));
    });
};

Outstanding Questions, 5/9/2014

  1. Jeremy's script runs but without the desired effects. For example, console.log(_this.lowest[k]) prints undefined, just as mine does. Further, the matched scores aren't skipped, which they should be.

  2. Jeremy's script specifies lowest as a ko.observable. My script also now has lowest as a ko.observable, but why shouldn't a plain JS array work for this? I only need lowest to update when the button it's bound to is clicked, and those bindings are already taken care of.

¿Fue útil?

Solución

That is how observables work in Knockout.

When you create one, you are creating a function.

var myObservable1 = ko.observable(); // Create it.
var myObservable2 = ko.observable("Hola!"); // Create it with a value.

console.log(typeof myObservable2); // It is indeed a function
console.log(typeof myObservable2()); // That returns a string
console.log(myObservable2()); // And get the value.

EDIT BASED ON QUESTION IN COMMENTS

var koTest = ko.observableArray();
koTest.push("Line0");
koTest.push("Line1");
koTest.push("Line2");
koTest.push("Line3");
koTest.push("Line4");

var jsTest = [];
jsTest.push("Line0");
jsTest.push("Line1");
jsTest.push("Line2");
jsTest.push("Line3");
jsTest.push("Line4");


alert(koTest()[2]);
alert(jsTest[2]);
alert(koTest()[2] === jsTest[2]);

Test Code

I went ahead and make a runnable test of your code and everything was working just fine for me. I had to make some assumptions about the contents of _this -- in particular the declaration of lowest, which I made an observableArray based on how you were accessing it.

Anyways, this code runs:

    var _this = {
        scores: ko.observableArray(),
        lowest: ko.observableArray()
    };


    var mean = (function(scores) {
        var m = 0;
        var count = 0;
        var k;


        ko.utils.arrayForEach(_this.scores(), function(score) {

            console.log([typeof score(), score()]);

            if (!isNaN(parseFloat(score()))) {
                k = _this.scores.indexOf(score);
                console.log(k);
                console.log(_this.lowest[k]);
                if (score() != _this.lowest[k]) {
                    m += parseFloat(score());
                    count += 1;
                }

            }


        });


        if (count) {
            m = m / count;
            return m.toFixed(2);
        } else {
            return 'N/A';
        }
    });

    for (var i = 0; i < 10; i++) {
        _this.scores.push(ko.observable(i));
    }

    var m = mean();
    alert(m);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top