【问题标题】:Knockout - How to access parent properties from nested function?淘汰赛 - 如何从嵌套函数访问父属性?
【发布时间】:2012-11-18 20:03:28
【问题描述】:

请问有人可以帮我吗?

执行 create 方法时出现以下错误:

*Uncaught TypeError: Object #<Object> has no method 'baseUri'*

从以下绑定调用此方法:

<form id="createProducts" data-bind="submit: products.create">

当执行 read 方法时,从 PreLoad 方法调用,baseUriitems 都可用.

当视图模型被定义为一个函数时,我已经找到了解决这个问题的方法,但在我的例子中,它被定义为一个对象。

这是我的完整 JS 文件


var mm = {

    /* Products ********************************************************** */

    products: {

        items: ko.observableArray([]),

        read: function () {
            $.getJSON(this.baseUri(), this.items);
        },

        create: function (formElement) {

            $.post(this.baseUri(), $(formElement).serialize(), null, "json")
                .done(function (o) {                    
                    alert("The Product " + o.Name + " was created.");
                    this.items.push(o);
                });
        },

        baseUri: function () { return BASE_URI; }
    }

};

function PreLoad() {

    mm.products.read();

    ko.applyBindings(mm);
}

  • BASE_URI 是在我的母版页中定义的全局变量,我需要它是因为我有多个嵌套视图模型(我从这段代码中删除了它们)并且每个 baseUri 都是 BASE_URI +“some_string_value”的组合。无论如何,我也需要访问 items,以更新列表中显示的值。

谢谢!

【问题讨论】:

    标签: javascript knockout.js nested-attributes


    【解决方案1】:

    有两种方法可以确保this在绑定事件时是正确的。

    首先是使用bind

    <form id="createProducts" data-bind="submit: products.create.bind(products)">
    

    第二种是使用内联函数:

    <form id="createProducts" data-bind="submit: function() { products.create(); }">
    

    这种行为将来可能会改变(请参阅https://github.com/SteveSanderson/knockout/issues/378)。

    编辑

    有两种解决方案可以使this 在回调函数中可用。第一种是将this 复制到一个局部变量,该变量将通过闭包获得。

            var self = this;
            $.post(this.baseUri(), $(formElement).serialize(), null, "json")
                .done(function (o) {                    
                    alert("The Product " + o.Name + " was created.");
                    self.items.push(o);
                });
    

    第二种是在回调函数上使用bind

            $.post(this.baseUri(), $(formElement).serialize(), null, "json")
                .done(function (o) {                    
                    alert("The Product " + o.Name + " was created.");
                    this.items.push(o);
                }.bind(this));
    

    【讨论】:

    • 谢谢迈克尔!第一个选项部分解决了这个问题。 this.baseUri 现在可用,但 this.items 未定义。可能是因为它在 .done(function. 里面
    • 正确。我也扩展了解决这个问题的答案。
    • 完美的迈克尔!我尝试过,但我将绑定放置在错误的位置(}).bind 而不是}.bind)。非常感谢!
    【解决方案2】:

    我有一种感觉,this 并不是你打电话给products.create 时所想的那样。尝试使用.bind 明确设置上下文:

    <form id="createProducts" data-bind="submit: products.create.bind($data)">
    

    【讨论】:

    • 你好安德鲁!我测试了你的建议,但保持不变。我读了一篇关于这个上下文问题的文章。根据第 5 项 (knockmeout.net/2011/06/…),~this~ 将代表调用者的上下文。本例中的表单,这就是为什么我的函数找不到项目或 baseUri 属性的原因。
    • 文章建议将“.bind(viewModel)”(我的代码中的mm)应用于函数,但错误仍然存​​在。
    • 如果你使用.bind($root)会怎样?
    【解决方案3】:

    正如 Andrew Whitaker 已经提到的 - “this”将不是您所期望的上下文。我的解决方案是存储“this”引用(例如称为“self”)并使用它而不是“this”:

    products: {
        self: undefined,
        items: ...,
        init: function() { 
            this.self = this; 
        },
        read: function () {$.getJSON(self.baseUri(), self.items);},
        create: function () {
            $.post(self.baseUri(), $(formElement).serialize(), null, "json")
                .done(function (o) {                    
                    alert("The Product " + o.Name + " was created.");
                    self.items.push(o);
                });
        },
        baseUri: function () { return BASE_URI; }
    };
    
    function PreLoad() {
    
        mm.products.init();
        mm.products.read();
    
        ko.applyBindings(mm);
    }
    

    你也可以明确指出应该在什么上下文中调用函数:

    <form id="createProducts" data-bind="submit: function () { products.create($root.products); }">
    
    products: {
        create: function(self) {
            ...
        }
    

    在这种情况下,$root 应该指向您的视图模型,因此您将传递产品对象的实例来创建函数。

    【讨论】:

    • 嗨@Slawek!感谢您提出的第一个建议,即让 html 的数据绑定尽可能简单。但不幸的是,错误仍然存​​在。 :( 第二个解决了问题,但增加了数据绑定的复杂性。今晚我会回到这个项目。谢谢!
    猜你喜欢
    • 2015-06-02
    • 1970-01-01
    • 1970-01-01
    • 2014-12-11
    • 2018-06-02
    • 2015-10-07
    • 1970-01-01
    • 1970-01-01
    • 2014-09-28
    相关资源
    最近更新 更多