Knockout JS:indexOf总是返回-1?

时间:2014-04-25 17:09:13

标签: javascript html knockout.js indexof ko.observablearray

背景

我正在尝试构建成绩簿应用程序,主要是作为学习练习。目前,我有两个模特,一个学生,一个作业。我决定将所有与分数相关的信息存储在学生中,而不是每个作业。也许有更好的方法。

无论如何,我已经获得了每个学生的平均分数,即她在课堂上的成绩。我现在正想要计算每项任务的平均分数。这是我遇到麻烦的地方,因为它有点棘手。我目前正在使用以下方法:

  

JS Bin (整个项目):http://jsbin.com/fehoq/84/edit

JS

  var _this = this;
  ...

  // get index i of current assignment; 
  // then, for each student, grab her grade for assignment i;
  // add each grade at i, then divide by # of students;
  // return this value (the mean);

  this.workMean = ko.computed(function (work) {
        var i = parseFloat(_this.assignments.indexOf(work)); 
        var m = 0;
        var count = 0;
        ko.utils.arrayForEach(_this.students(), function (student) {
            if (!isNaN(parseFloat(student.scores()[i]))) {
                m += parseFloat(student.scores()[i]);
            } else {
                count += 1;
            }
        });
        m = m / (_this.students().length - count); 
        return m.toFixed(2);   
    });

我将以下列方式将其绑定到HTML:

HTML

<tbody>
  <!-- ko foreach: students -->
    <tr>
        <td><input data-bind="value: fullName + ' ' + ($index()+1)"/></td>  
        <!-- ko foreach: scores -->  
        <td><input data-bind="value: $rawData"/></td>
        <!-- /ko --> 
        <td data-bind="text: mean" />
        <td><input type="button" value="remove" data-bind="click: $root.removeStudent.bind($root)". /></td>
    </tr> 
  <!-- /ko -->
    <tr>
      <td>Class Work Average</td> 
      <!-- ko foreach: assignments -->
      <td data-bind="text: $root.workMean"></td>
      <!-- /ko -->
    </tr>  
</tbody>    

问题是我在这里做的事情 - 我认为这是workMean()方法 - 完全破坏了我的应用程序。在尝试调试时,我注意到如果我只是注释掉整个方法save i,然后返回i并将其绑定到较低的foreach: assignments,它会一直返回-1 (每项任务)。

Knockout文档告诉我,当我打电话给indexOf时,这意味着没有匹配,但我为什么会迷失方向。指导赞赏。

1 个答案:

答案 0 :(得分:3)

除了DCoder identified - observables没有参数 - 的问题,你还有另一个错误:

score = parseFloat(student.scores()[i]);

应该是

score = parseFloat(student.scores()[i]());

你在那里访问的可观察数组的第n个(或第i个)元素本身就是一个可观察的元素,所以之前,你将函数传递给parseFloat,它总是产生NaN。

以下是工作版本:http://jsbin.com/lejezuhe/3/edit

顺便说一句:在DCoders改变后,

<td data-bind="text: $root.workMean($data, $index())"></td>

与正常函数绑定,而不是可观察函数。那么为什么这仍然有用?

RP Niemeyer, one of the Knockout core members writes

  

在Knockout中,绑定是使用dependentObservables在内部实现的,因此您实际上可以使用普通函数代替绑定中的dependentObservable。绑定将在dependentObservable中运行您的函数,因此任何访问其值的observable都将创建一个依赖项(您的绑定将在更改时再次触发)。

(曾经被称为计算的observables&#34; dependentObservables&#34;在早期版本的Knockout中)

对于这些类型的问题,熟悉调试器(例如Chrome Developer Tools中的调试器)确实很有帮助。能够逐行浏览代码并查看实际包含的参数和变量非常有用。

在调试绑定时,Chrome Knockout context debugger值得拥有,因为您可以单击任何DOM元素并查看绑定上下文:

Screenshot depicting the Knockout context debugger in action

最后,在控制台中使用ko.dataFor()可以让您查看绑定到DOM的任何现有Knockout模型和视图模型:

Screenshot depicting the usage of ko.dataFor() in the dev tools console

在Chrome控制台中,$0始终是对您当前在“元素”面板中选择的DOM元素的引用 - 此处为<td>