【问题标题】:Create a computed observable for formatted values for a bunch of variables为一堆变量的格式化值创建一个计算的 observable
【发布时间】:2012-12-09 10:00:46
【问题描述】:

我在视图模型中有 3 个可观察变量,并希望输出为格式化值。但是,我不想为它们中的每一个编写计算方法,因为它们是相同的。重用代码的最佳方法是什么?谢谢。

我要实现的代码是:

   this.formattedPrice = ko.computed({
        read: function () {
            return '$' + this.price().toFixed(2);
        },
        write: function (value) {
            // Strip out unwanted characters, parse as float, then write the raw data back to the underlying "price" observable
            value = parseFloat(value.replace(/[^\.\d]/g, ""));
            this.price(isNaN(value) ? 0 : value); // Write to underlying storage
        },
        owner: this
    });

失败的例子在:Jsfiddle

谢谢,

【问题讨论】:

    标签: knockout.js formatted computed-observable


    【解决方案1】:

    您可以通过以下几种方法使其可重复使用。

    如果你想在你的视图模型中处理这个问题,那么一个不错的选择是创建一个扩展,它将格式化的计算 observable 存储为原始的“sub-observable”。您可以使用extenders 或通过添加到共享的fn 对象来扩展可观察对象,如here 所述。我更喜欢后者。

    因此,您可以向 observables 添加一个名为 withCurrencyFormat 的函数。它可能看起来像:

    ko.observable.fn.withCurrencyFormat = function(precision) {
        var observable = this;
        observable.formatted = ko.computed({
            read: function (key) {
                return '$' + (+observable()).toFixed(precision);
            },
            write: function (value) {
                value = parseFloat(value.replace(/[^\.\d]/g, ""));
                observable(isNaN(value) ? null : value); // Write to underlying storage 
            }        
        }); 
    
        return observable;
    };
    

    现在,你可以说:

     self.week1Amount = ko.observable(w1).withCurrencyFormat(2);
     self.week2Amount = ko.observable(w2).withCurrencyFormat(2);
     self.week3Amount = ko.observable(w3).withCurrencyFormat(2);
    

    并在 UI 中对其进行绑定,例如:

        <td><input data-bind="value: week1Amount.formatted" /></td>
        <td><input data-bind="value: week2Amount.formatted" /></td>
        <td><input data-bind="value: week3Amount.formatted" /></td>
    

    示例:http://jsfiddle.net/rniemeyer/xskJN/

    另一种选择是将它移动到绑定中,这样您就可以不理会您的视图模型。这将使用类似的代码,但在自定义绑定处理程序中可能如下所示:

    ko.bindingHandlers.valueAsCurrency = {
        init: function(element, valueAccessor) {
            var observable = valueAccessor(),
                formatted = ko.computed({
                    read: function (key) {
                        return '$' + (+observable()).toFixed(2);
                    },
                    write: function (value) {
                        value = parseFloat(value.replace(/[^\.\d]/g, ""));
                        observable(isNaN(value) ? null : value); // Write to underlying storage 
                    },
                    disposeWhenNodeIsRemoved: element                
                });
    
            //apply the actual value binding with our new computed
            ko.applyBindingsToNode(element, { value: formatted });
        }        
    };
    

    因此,在绑定处理程序中,我们创建了我们的计算对象,然后对它使用 value 绑定。

    现在,您的视图模型不需要更改,您可以像这样在 UI 中进行绑定:

        <td><input data-bind="valueAsCurrency: week1Amount" /></td>
        <td><input data-bind="valueAsCurrency: week2Amount" /></td>
        <td><input data-bind="valueAsCurrency: week3Amount" /></td>
    

    示例:http://jsfiddle.net/rniemeyer/sD6y4/

    【讨论】:

    • 我还有一个问题,如何将它应用到 sum 字段,它是只读的。同样,我不工作的代码是jsfiddle.net/sD6y4/4。因为我有 sum1, sum2, ..., 字段。在这种情况下是否可以制作可重用的功能?提前致谢!
    • 您可以添加一个 textAsCurrency 绑定,它只执行 read 部分并应用 text 绑定。可能看起来像:jsfiddle.net/rniemeyer/3nrKD
    • 很酷的方式。我不知道有这么多方法可以解决它。现在我有另一个问题:通过 ajax 从服务器更新模型后,UI 没有刷新。我想这是因为我使用的是数组。示例为jsfiddle.net/3nrKD/1。有可能让它工作吗?非常感谢。
    • 请忽略我之前的评论。我发现了这个问题,并让它在这里工作,jsfiddle.net/3nrKD/3。谢谢。
    • 嗨,RP。我找到了一个例子,比如jsfiddle.net/3nrKD/5。所以我的理解是,如果你更新可观察变量 week1Amount,那么 UI 就会更新。但是如果你创建一个新的。它没有改变。我的理解对吗?谢谢。
    猜你喜欢
    • 2018-11-19
    • 2013-11-07
    • 2019-05-29
    • 1970-01-01
    • 1970-01-01
    • 2020-04-07
    • 1970-01-01
    • 2022-01-18
    • 2016-11-25
    相关资源
    最近更新 更多