【问题标题】:Knockout.js: computed observables on optionally defined valuesKnockout.js:根据可选定义的值计算 observables
【发布时间】:2013-11-25 02:40:19
【问题描述】:

我为 Yesod(一个 Haskell Web 框架)编写了一个简洁的小 knockout.js 绑定,但是我在处理可选定义的值时遇到了一些麻烦。绑定的 Haskell 部分旨在提供 javascript 片段,该片段对同一处理程序进行 Ajax 调用,并接收由 ko.mapping 解析的 JSON 对象。还有一些用于自定义的钩子。

这一切都很好,但我在处理可选值时遇到了问题。如果我提供一个带有可选记录的值,JSON 发射器会将其视为可选并且不会发射它。

因此,例如,请求的 JSON 响应

data Foo = Foo { bar :: Maybe Int 
               , baz :: Int
               }
serveThis :: Foo
serveThis = Foo (Nothing) 0

是 { baz: "0" }

我明白为什么会这样,并且我可以改变它(但如果可能的话,我宁愿不这样做)。问题是当我在 serveThis 的 JSON 表示上调用 ko.mapping.fromJS 时,bar 字段没有变成可观察的。好的,我也明白了。我可以使用 with 绑定来进行条件数据绑定。但我不知道足够的 JavaScript 来有条件地定义计算的 observables。

我的真实代码如下:

var ViewModel = function (data) {
  ko.mapping.fromJS(data, {}, this);

  this.notes.stdDev.percent = ko.computed( function () {
    return numeral( this.notes.stdDev() ).format("0%");
  }, this); 
}

所以,如果标准偏差没有在 Haskell 端定义,它就不会作为 JSON 字段发出,因此 ko.mapping 不会使其成为可观察的。那么如何有条件地定义百分比表示呢?

【问题讨论】:

    标签: javascript knockout.js


    【解决方案1】:

    stdDev 属性被省略的情况下,您的视图模型是否也会省略该属性?或者,无论初始值如何,您的视图模型是否都需要包含属性的关联可观察对象?

    如果是前者,那么您只需要包含一些类似于以下的简单条件逻辑:

    this.notes.stdDev.percent = ko.computed(function() {
        return this.notes.stdDev ? this.notes.stdDev * 100 + "%' : 'n/a';
    }, this);
    

    这将检查是否存在stdDev 属性并返回静态值'n/a' 如果该属性未定义。

    但是,如果您的视图需要所有用户输入一个 stdDev 值,即使省略了初始值,我也不建议使用此模型。相反,您可能要考虑放弃 ko.mapping。大约一年前,我广泛使用了 ko.mapping,但我最近使用它的频率有所降低,因为我使用 JS 模型获得了更好的结果。这是一个最近为我工作的视图模型架构示例。

    var viewModel = (function () {
        return { init: init };
    
        function init(data) {
            var self = {
                notes: ko.observable()
            };
    
            self.notes(new Notes(data));
            ko.applyBindings(self);
            return self;
        }
    
        function Notes(data) {
            return {
                stdDev: ko.observable(data.notes),
                otherProp: ko.observable(data.otherProp),
            }
        }
    }());
    

    要注意的主要事情——至少在映射讨论的上下文中——是Notes 构造函数。虽然可能会复制从您的服务层返回的模型,但这种模式允许可靠的数据结构,而不是映射解决方案。在决定它不适用于所有情况之前,我与映射进行了 6 个月的斗争,这个明确的模型定义确实为您的视图模型增加了清晰度和可靠性。尽管映射可以简化您的管道代码,但它确实对传入数据的结构产生了不必要的依赖。事实仍然是,如果您的视图引用了您的视图模型中不存在的属性,您的视图将会崩溃。

    如果您reeeeeally想要避免在两个层之间重复模型,有一个折中的解决方案,您可以为您所依赖的属性定义默认值,并使用默认值扩展您的传入数据模型缺失时的值。 jQuery 的extend 函数非常适合这个函数——如果你已经依赖于 jQuery。举个例子:

    var noteDefaults = {
        stdDev: 0
    };
    var input = $.extend({}, defaults, data);
    ko.mapping.fromJS(input, {}, this);
    

    希望这会有所帮助!

    【讨论】:

    • 您好,感谢您的帮助。我非常有信心下层是正确的,所以我真的很想推导出 ko 级别的视图。我的问题中有一个错字,这使您对在 stdDev 属性上使用条件逻辑的建议不适用(由于未定义该方法,我遇到了崩溃),但是您对 jQuery 扩展的引用非常酷。您对 ko.extender 有意见吗?
    • 我更新了我的答案,试图修复条件语句中的 JS 错误。我假设您在某处有一个名为numeral 的自定义函数。如果这仍然没有帮助,请提供有关您收到的错误的更多信息以及所需的行为是什么?如果源值未定义,您希望百分比值返回什么?
    • 那你搞定了吗,@nomen?如果我能提供任何进一步的帮助,请告诉我:)
    猜你喜欢
    • 1970-01-01
    • 2014-04-25
    • 2023-03-17
    • 2014-08-28
    • 1970-01-01
    • 1970-01-01
    • 2016-03-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多