knockout.js - "TypeError: object is not a function"使用 knockout 和 Breeze 时

标签 knockout.js breeze

问题

I got a "TypeError: object is not a function" error when EntityManager.saveChanges. The error arises before breeze sends anything to the server.

When I read the (long) stack trace, I see that the error is thrown inside a Breeze method called InitializeEntityPrototype.prototype.getProperty.



还有其他地方可能会遇到此错误;这恰好是我今天发现它的地方。

原因

请注意,我的应用程序使用 Knockout (ko)。这意味着我的实体模型由期望 的 Breeze “ko”模型适配器管理。每个数据属性 成为 ko.observable (observableobservableArray )。这意味着您的属性值实现为 功能 ,而不是原始数据类型、数组或对象。

Breeze 用可观察的属性初始化我的实体,所以我不必自己做。但这取决于我在我的代码中设置实体模型时保留这些可观察值 .

ko 编程中最常见的错误之一是设置属性而不是调用属性 setter 。
todo.Description("foo");  // Correct ... call the ko.observable assignment function
todo.Description = "foo"; // WRONG ... wipes out the observable function !!!

当我错误地将“foo”分配给 todo.Description 时,可观察函数消失了……Breeze 监视该属性更改的能力也消失了。

我的数据绑定(bind) HTML 控件可能会继续工作。 Knockout 不必绑定(bind)到 observable;它将愉快地绑定(bind)到原始数​​据值。但现在这变成了 一次性只读绑定(bind) .该属性不再是可观察的。对该属性的后续更改将不会传播到屏幕。

换句话说,我的错误分配会导致 UI 行为出现静默错误。

但是当 Breeze 尝试处理该属性时,我的错误并没有沉默。 Breeze 假设实体数据属性是一个 ko 函数。 Breeze ko 模型适配器不需要检查......它只是调用它假定的函数。这是(内部)实体getProperty执行:
proto.getProperty = function (propertyName) {
  return this[propertyName]();
};

如果this[propertyName],您可以看到为什么会抛出异常。是函数以外的任何东西。

对我来说可悲的是,这个错误很可能是在 Breeze 操作的深处发生的。错误消息“对象不是函数”(或类似的东西)可能是关于任何东西的。我不太可能建立联系。

这个 S.O.问题提醒您寻找这个特定的原因。

该怎么办?

这分明是我的错。现在我必须找到我分配实体属性的位置而不是调用函数......并修复它。

我的搜索取决于知道属性名称。当前的错误消息没有告诉我名称。所以我必须对代码进行断点并在抛出错误时捕获它。

一个“简单”的权宜之计是用 try/catch 临时在 Breeze .debug.js 中对这个方法进行修补。版本。
  • 在编辑器中打开 Breeze .debug.js
  • 找到“return this[propertyName]();
  • 将其更改为:
    proto.getProperty = function(propertyName) {
      try {
        return this[propertyName]();
      } catch (err) {
        debugger;
        err.message = propertyName + ' is not a ko function; did you wipe it out by assignment?\n' + 
                      (err.message || '');
        throw err;
      }
    }
    
  • 打开开发者工具再次运行应用程序

  • 它应该停在 debugger您将在其中了解属性名称和所涉及的实体的行。

    Breeze 是否应该提供更丰富的错误信息?

    如果 Breeze 为我撰写此消息,那就太好了。事实上,团队正在考虑这样做。

    主要障碍是性能。 getPropertysetProperty方法正走在热门道路上。他们经常被调用,尤其是在查询结果实现期间。 Breeze 团队对这个敏感领域的额外逻辑持谨慎态度。我们不希望每个人都付出高昂的代价来捕捉开发人员错误,至少不是在生产(缩小)Breeze 库中。

    让我们给 Breeze 团队时间来解决这个问题。

    最佳答案

    您的问题写得很好,涉及一个常见问题,并且可能对其他搜索此特定问题的人有所帮助。但是,它可能仍在征求意见。

    任何状况之下...

    我和我的同事将您的情况中的问题称为“knockout 税”:您必须处理一些编程不便,以换取使用出色的 MVVM 库。当您使用 data-bind="visible: !myObservable" 时,会出现相同问题的不同实例。并忘记将其作为函数执行以获取值。

    回答这个问题:不,我认为 Breeze 不应该处理这个问题,至少不应该使用更丰富的错误消息。如果有的话,我认为如果您处于问题的情况下,有三种不同的选择:

  • 将 Typescript 用于您自己的代码。如果 DescriptionKnockoutObservable<string>如果您为其分配常规字符串,则编译器会提示。
  • 在您自己的代码中或作为适当框架的补丁:将 observables 的属性设置为只读。 Along these lines .但是,this method依赖于浏览器支持...
  • 切换到另一个没有这个“税”的 MVVM 框架。例如,AFAIK Angular 没有 Knockout 所具有的这种类似“功能”的设置;它使用常规属性。

  • 但这只是我的 2 cts - 阅读我自己的答案,我确实觉得这(“情况 X 应该由框架 Y 处理吗?”)都是见仁见智的问题。

    关于knockout.js - "TypeError: object is not a function"使用 knockout 和 Breeze 时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27713308/

    相关文章:

    javascript - knockout 脏标志代码不起作用

    javascript - Breeze 续集 - 警告续集版本已过时 3.x 有一个关键的安全修复

    angularjs - Angular -ui-select2和breezejs : load ajax list after typing in 2 characters

    javascript - Breeze 多对多关系以及在迭代问题上将 Aspect 设置为 'setDeleted'

    javascript - Knockout JS 绑定(bind)计算可观察值不起作用

    html - 如何防止 knockout 从 IE8 跨度同级中剥离空文本节点

    javascript - knockout 时不完全结合

    knockout.js - 是否可以将 KnockoutJS 与屏蔽输入一起使用?

    angularjs - Angular/Breeze Initializer 中的 KO.Computed 等效项

    javascript - Angular Breeze 设置