淘汰消毒数字

时间:2012-09-06 14:08:01

标签: knockout.js knockout-mapping-plugin knockout-2.0 knockout-validation

我正在使用knockout和映射插件来自动创建我的视图模型。我在视图模型中有一堆金额,我绑定到文本框。当用户更改文本框中的金额时,我想要的是确保他们输入的是一个数字,并且它大于0,如果不是,我想用0替换他们输入的内容。这看起来像它应该很简单......使用自定义绑定或订阅功能。

我正在阅读的关于敲门验证的所有内容都涉及扩展器和读/写计算的可观察量,或者添加另一个插件(例如jquery验证)。对于这种情况,它们似乎都有点过分,并且必须为要验证的每个observable显式声明扩展器/计算的observable。我有很多使用映射插件自动创建的金额,所以这似乎不合理。

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:7)

对于您的特定方案,处理此问题的一种方法是创建一个能够拦截该值并进行验证的自定义绑定。这可以通过在自定义绑定中创建可编写的可写入来进行绑定来完成。优点是您不必担心自定义对象创建的映射插件。

它可能看起来像:

ko.bindingHandlers.positiveNumericValue = {
    init : function(element, valueAccessor, allBindingsAccessor) {
        var underlyingObservable = valueAccessor();
        var interceptor = ko.computed({
            read: underlyingObservable,
            write: function(newValue) {
                var current = underlyingObservable(),
                    valueToWrite = isNaN(newValue) ? 0 : parseFloat(+newValue);

                if (valueToWrite < 0) {
                   valueToWrite = 0;   
                }

                //only write if it changed
                if (valueToWrite !== current) {
                    underlyingObservable(valueToWrite);
                } else {
                    //if the rounded value is the same as it was, but a different value was written, force a notification so the current field is updated to the rounded value
                    if (newValue !== current) {
                        underlyingObservable.valueHasMutated();
                    }
                }   
            } 
        });
        ko.bindingHandlers.value.init(element, function() { return interceptor }, allBindingsAccessor);
    },  
    update : ko.bindingHandlers.value.update
};

以下是一个示例:http://jsfiddle.net/rniemeyer/2TnSM/

另一种方法是使用一个选项来扩展observable,以创建可写的计算。

对于您的方案,它可能如下所示:

ko.observable.fn.forcePositive = function() {
    var underlyingObservable = this;
    if (!this.forcePositiveInterceptor) {
         this.forcePositiveInterceptor = ko.computed({
            read: this,
            write: function(newValue) {
                var current = underlyingObservable(),
                    valueToWrite = isNaN(newValue) ? 0 : parseFloat(+newValue);

                if (valueToWrite < 0) {
                   valueToWrite = 0;   
                }

                //only write if it changed
                if (valueToWrite !== current) {
                    underlyingObservable(valueToWrite);
                } else {
                    //if the rounded value is the same as it was, but a different value was written, force a notification so the current field is updated to the rounded value
                    if (newValue !== current) {
                        underlyingObservable.valueHasMutated();
                    }
                }   
            } 
        });
    }            

    return this.forcePositiveInterceptor;        
};

然后你会绑定它,如:

<input type="text" name="age" data-bind="value: age.forcePositive()" />

我在这里实现它的方式,你需要调用函数forcePositive(),以便初始化可写函数。这样您就可以在没有任何自定义的情况下使用映射插件,只需在要使用此功能的任何observable上执行此操作。

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

我认为这两种选择都适用于您的场景。我可能赞成第二种选择,这样你就可以在使用普通绑定时添加更多这些选择。

答案 1 :(得分:1)

快速小巧的

http://jsfiddle.net/gxfup/1/

编辑:

我不想让映射插件定义我的viewmodels,我使用原型视图模型(就像上面的例子中一样,然后让mapper插件映射到那里)。

ViewModel = function (data) {
    this.number = ko.observable().extend({ number: true });
    return ko.mapping.fromJS(data, {}, this);
};