【问题标题】:Knockout arrayForEach undefined property淘汰 arrayForEach 未定义的属性
【发布时间】:2015-08-06 13:44:17
【问题描述】:

我在尝试从可淘汰的可观察数组中的每个项目中获取一个数字并将这些数字相加并将其分配给另一个计算变量时遇到了麻烦。这就是我现在所拥有的......

Semesters: ko.observableArray([
    {
        semesterName: "Fall",
        semesterCode: "300",
        PlannedCourses: ko.observableArray([]),
        totalCredits: ko.computed(function(){
            var total = 0;
            ko.utils.arrayForEach(this.PlannedCourses, function (course) {
                total += course.MinHours();
            });

            return total;
        }),
    },
    ...

我正在尝试做的是,在 totalCredits 变量中,我尝试遍历 PlannedCourses 数组并获取每个项目的 MinHours 变量并将它们一起添加到总变量中。然后我将它返回到 Semesters 数组中的 totalCredits 项。我遇到的问题是在 ko.utils.arrayForEach 部分中获取 PlannedCourses 变量。我得到一个未定义的,我不知道为什么。我认为这是一个简单的语法错误,但我看不出有什么问题。

PlannedCourses 可观察数组是一个动态对象,可以正确获取 PlannedCourses 列表。它是在自身的上下文中定义的,但我没有正确地将它传递给 totalCredits 计算函数。

我希望这已经足够清楚了。感谢您的帮助!

注意:所有其余代码都按预期工作。唯一不起作用的部分是 totalCredits 计算函数。我不确定 ko.utils.arrayForEach 中的任何内容是否正常工作,因为我还没有做到这一点。

【问题讨论】:

    标签: javascript function knockout.js


    【解决方案1】:

    您将需要更改填充 Semesters 可观察数组的方式以使用构造函数,以便获得对 this 正确范围的引用:

    function semester(name, code) {
        this.Name = name;
        this.Code = code;
        this.PlannedCourses = ko.observableArray([]);
        this.totalCredits = ko.computed(function(){
            var total = 0;
            ko.utils.arrayForEach(this.PlannedCourses(), function (course) {
                //Note the change to "this.PlannedCourses()" above to get the underlying array
                total += course.MinHours();
            });
    
            return total;
        }, this); //now we can pass "this" as the context for the computed
    }
    

    看看我们现在如何将一个对象传递给ko.computed 的第二个参数,以用作内部函数中this 的上下文。如需更多信息,请参阅淘汰赛文档:Managing 'this'

    然后在填充数组时创建 semester 的新实例:

    Semesters: ko.observableArray([
        new semester("Fall", "300"),
        new semester(...)
    ]);
    

    这种方法还意味着您有一种一致的方式来创建您的 semester 对象(计算只为一件事定义一次),而不是可能在您最初可能有的任何重复中包含拼写错误等。

    【讨论】:

    • 这可能是最好的方法。我将不得不做很多重组,但毫无疑问我应该这样做。我很感激。我正在尝试合并几种不同的 viewModel 方法,这使事情变得复杂。现在,“学期”是另一个数组“年”的一部分,该数组具有“学术工作”和“学期”,其结构与“学期”的结构非常相似。如果我按照您指定的方式修改两个列表,这应该可以。不过,这需要一些时间。如果这有效,我会尽快回复您。再次感谢!
    • 如果您要创建具有相同属性/功能等的多个对象,这将是通常的方法
    【解决方案2】:

    正如其他人已经提到的那样,您的this 不是您认为的那样。在您的情况下,上下文应按如下方式传递给计算:

    totalCredits: ko.computed(function() {
        // Computation goes here..
    }, this)
    

    另一种方法是在对象创建期间将正确的this 存储到某个局部变量(例如var self = this;,然后使用self 而不是this)。

    但是,ko.utils.arrayForEach 不适用于可观察数组,但适用于纯 JavaScript 数组,因此您应该打开可观察数组以访问底层数组的元素:

    ko.utils.arrayForEach(this.PlannedCourses(), function(course) { 
        // ...
    });
    
    // Or
    
    ko.utils.arrayForEach(ko.unwrap(this.PlannedCourses), function(course) { 
        // ... 
    });
    

    【讨论】:

    • “但是,ko.utils.arrayForEach 不适用于可观察数组,但适用于纯 JavaScript 数组”我不知道这一点。谢谢你。我已经编辑了我的代码以使用 ko.unwrap 并将 self 分配给它。不过,我仍然对 PlannedCourses 没有定义。让我再看一下,看看我是否能弄清楚我的错误范围之外发生了什么......
    【解决方案3】:

    范围(this)不是你想象的那样。

    http://knockoutjs.com/documentation/computedObservables.html

    尝试添加您的上下文,如下所示:

    Semesters: ko.observableArray([
    {
        semesterName: "Fall",
        semesterCode: "300",
        PlannedCourses: ko.observableArray([]),
        totalCredits: ko.computed(function(){
            var total = 0;
            ko.utils.arrayForEach(this.PlannedCourses, function (course) {
                total += course.MinHours();
            });
    
            return total;
        }, this), // new context passed in here
    },
    ...
    

    这样做会将数组项本身的上下文传递到您的计算函数中。

    编辑: 您可能需要访问循环内的 Semesters 对象,并添加一些方法来引用当前项目:

    Semesters: ko.observableArray([
    {
        semesterName: "Fall",
        semesterCode: "300",
        PlannedCourses: ko.observableArray([]),
        totalCredits: ko.computed(function(){
            var total = 0;
            for( var i = 0, len = Semesters().length; i < len; i++ ) {
                // check current array item, possibly add an id?
                if( Semesters()[i].semesterName === "Fall" &&
                    Semesters()[i].semesterCode === "300" ) {
    
                    ko.utils.arrayForEach(Semesters()[i].PlannedCourses, function (course) {
                       total += course.MinHours();
                    });
                    break; // done searching
                }
            }
    
            return total;
        })
    },
    

    【讨论】:

    • 随着对象的构建方式,this 甚至在外部范围内也不是正确的。
    • @JamesThorpe 我的想法完全正确
    • 看来@JomesThorpe 是对的。对于 PlannedCourses,我仍然没有定义。我 100% 确定它也在 PlannedCourses 上。当注释掉 totalCredits 的计算函数时,未定义的错误消失了。在控制台中,当我查看: da.vm.Years()[0].Semesters()[0].PlannedCourses() 时,我按预期获得了 PlannedCourses 数组中的对象列表。所以列表正在填充......
    • @JoshSalazar,我认为您需要基于根 Semester 数组的查找。检查我的编辑
    • @JoshSalazar 虽然这可能有效,但我真的建议您不要长期采用这种方法。使用 JavaScript 及其作用域的工作原理。
    猜你喜欢
    • 2012-03-06
    • 2017-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多