将项目插入数组后,KnockoutJS ko.computed()不会更新

时间:2013-01-26 23:55:30

标签: knockout.js

我有以下对象:

function Category (id, name, weight) {
    this.categoryId = ko.protectedComputed(id);
    this.name  = ko.protectedComputed(name); 
    this.weight = ko.protectedComputed(weight);
    // this.dirtyFlag = new ko.dirtyFlag(this);
}

function Item (id, name, categoryId, gradeMax) {
    this.itemId = ko.observable(id);
    this.name  = ko.observable(name); 
    this.categoryId = ko.observable(categoryId);
    this.gradeMax = ko.observable(gradeMax);
}

function Grade (gradeId, itemId, studentId, studentName, grade) {
    this.gradeId = gradeId;
    this.itemId =  itemId;
    this.studentId  =  studentId; 
    this.studentName = studentName;
    this.grade = ko.observable(grade);
}

var viewModel =  function () {
    var self = this;

    self.items = ko.observableArray([
        new Item(3, "Homework 3", 1, 10),
        new Item(1, "Homework 1", 1, 20),
        new Item(2, "Homework 2", 1, 30),
        new Item(4, "Quiz", 3, 5)
    ]);

    self.categories = ko.observableArray([ 
        new Category(1, "Homework", 50) , 
        new Category(2, "Test", 25), 
        new Category(3, "Quiz", 25)          
    ]);

    self.grades = ko.observableArray([  
        //grades for item 4
        new Grade(10, 4,1, "Olivo,  Omar", 2)  ,   
        new Grade(11, 4,2, "Mercado,  Coryann",5),           
        new Grade(12, 4,3, "Pena,  Juan", 4) 
    ]);

    self.addItem = function () {
        var randId = int.rand(); 
        var newItem = new Item(randId , "new item", 1, 100);
        self.items.push(newItem);

        self.selectedItem(newItem);           
    };

    self.getStudentAverage = function (studentId) {
        return ko.computed(function () 
        {
            var total = 0,
            numOfItems = 0;

            // Get the grades for the assignment for this student
            var studentGrades =   ko.utils.arrayFilter(self.grades(), function(grade) {                          
                return grade.studentId == studentId;
            }); 

            // Calculate the Weighted Average
            if ( self.isWeighted() == true ){
                var faceAverage= 100;

                return tempAvg ;
            }  
        }, this)();
    };
};

HTML

<tbody data-bind="foreach: { data : $root.students, as : 'student' }  "  >                  
   <tr> 
        <td>
                <span data-bind="text: student.studentId" ></span>   - 
                <span data-bind="text: student.studentName" ></span>  
        </td>

        <td> 
             <span data-bind="text:  $root.getStudentAverage(student.studentId) "> </span> 
        </td>

        <!-- ko foreach: { data : $root.items, as : 'item' }  -->             
        <td > <!--   <span data-bind="css: { dirty : $root.getGrade(item.itemId(), student.studentId).grade.isDirty()}"></span> -->
              <input  class="grade-input" data-bind="value: $root.getGrade(item.itemId(), student.studentId).grade " />  
        </td>          
        <!-- /ko -->
    </tr>
</tbody>

问题是当我插入新项目时vm.getStudentAverage()没有更新。 我想弄清楚为什么这对我不起作用。我想在插入新项目后计算每个学生的平均值。

这是展示问题的fiddle

2 个答案:

答案 0 :(得分:2)

您的代码中存在缺失的部分,但主要问题似乎是您在该函数中返回计算的observable的初始值,而不是计算的observable本身。所以最后,你绑定的是一个值而不是计算的observable。

self.getStudentAverage = function (studentId)
{
    return ko.computed(function () 
    {
        // code...
    }, this)(); // <-- you are returning the result of the computed
};

只需返回计算结果,不要调用它(使用额外的())。

更新的代码:

self.getStudentAverage = function (studentId)
{
    return ko.computed(function () 
    {
        // code...
    }, this);
};

注意:在您提供的代码中,您甚至没有引用计算内的items数组。您必须使用items数组才能在项目更改时更新计算。否则,计算不依赖于项目,因此没有理由更新它。

答案 1 :(得分:0)

问题是getStudentAverage只是一个返回计算的observable的函数。它必须是一个可观察的本身。我看到你试图让它使用studentId参数,但这只是你设计中出错的一种解决方法:

您需要Student模型,然后您可以循环播放一组学生并拨打student.getAverage之类的内容。无需再潜入id了。