1

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

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

任何帮助将不胜感激!

4

2 回答 2

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/

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

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

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(),以便初始化可写对象。这样您就可以使用映射插件而无需任何自定义,只需在您想要使用此功能的任何可观察对象上执行此操作。

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

我认为这两种选择都适合您的情况。我可能更喜欢第二种选择,这样您就可以在使用普通绑定时添加更多这些。

于 2012-09-06T15:31:27.193 回答
1

一个又快又小的

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

编辑:

我不喜欢让映射插件定义我的视图模型,我使用原型视图模型(就像上面的示例一样,然后让映射器插件映射到它上面)。

ViewModel = function (data) {
    this.number = ko.observable().extend({ number: true });
    return ko.mapping.fromJS(data, {}, this);
};
于 2012-09-06T15:38:47.263 回答