【问题标题】:Knockout Sanitize Numbers淘汰赛清理数字
【发布时间】:2012-08-31 09:16:02
【问题描述】:

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

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

任何帮助将不胜感激!

【问题讨论】:

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


    【解决方案1】:

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

    它可能看起来像:

    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/

    另一种方法是使用创建可写计算的选项来扩展可观察对象。

    对于您的场景,它可能如下所示:

    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/

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

    【讨论】:

    • 感谢详细的回复!令我惊讶的是,如此简单的东西似乎应该是任何类型的输入的标准,却必须如此复杂。这是在写入之前对用户输入的简单检查。我想这就是它必须的样子。我会尝试你的解决方案,并在今天下午晚些时候确认。再次感谢。
    • 您可以尝试简化代码,但上面的解决方案旨在有效地处理各种场景,并允许您继续使用映射插件而无需自定义对象创建。祝你好运!
    • 您没有任何问题,我刚刚测试了它,它运行良好。我只是说,对于这种简单和标准的情况,淘汰赛似乎应该提供更简单的解决方案。
    【解决方案2】:

    一个又快又小

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

    编辑:

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

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

    【讨论】:

    • 似乎您需要在声明时将扩展器应用于视图模型中的每个可观察数字。我正在使用映射插件来自动创建我的视图模型,所以我所有的 number observables 都已经创建了,因此我用 vm.number = ko.observable(0).extend({ number : 真的 });另外,我的模型中有很多可观察的数字,我不想将其明确应用到其中的每一个。
    猜你喜欢
    • 2013-04-10
    • 1970-01-01
    • 2015-03-20
    • 2012-04-08
    • 1970-01-01
    • 2016-03-15
    • 2023-04-03
    • 1970-01-01
    • 2016-09-03
    相关资源
    最近更新 更多