淘汰赛自定义数字绑定

时间:2014-01-23 11:17:40

标签: javascript jquery knockout.js

我想使用这种技术:make an input only-numeric type on knockout

允许用户只输入数字。

但是,此技术不会更新UI上的可观察值。

HTML:

 <span data-bind="text: Interval" ></span>
 <input data-bind="numeric: Interval" />

结合:

ko.bindingHandlers.numeric = {
    init: function (element, valueAccessor) {
        $(element).on("keydown", function (event) {
            // Allow: backspace, delete, tab, escape, and enter
            if (event.keyCode == 46 || event.keyCode == 8 || event.keyCode == 9 || event.keyCode == 27 || event.keyCode == 13 ||
                // Allow: Ctrl+A
                (event.keyCode == 65 && event.ctrlKey === true) ||
                // Allow: . ,
                (event.keyCode == 188 || event.keyCode == 190 || event.keyCode == 110) ||
                // Allow: home, end, left, right
                (event.keyCode >= 35 && event.keyCode <= 39)) {
                // let it happen, don't do anything
                return;
            }
            else {
                // Ensure that it is a number and stop the keypress
                if (event.shiftKey || (event.keyCode < 48 || event.keyCode > 57) && (event.keyCode < 96 || event.keyCode > 105)) {
                    event.preventDefault();
                }
            }
        });
    }    
};

因此,绑定不允许输入除数字以外的字符,但是当焦点在input上丢失时,相应的observable不会更新(因此span元素不会更改)。

注意:

我不需要允许用户在输入中输入非数字字符。我知道有其他解决方案,如ko数字扩展,将所有内容转换为数字,但我不需要这个。我需要一个只允许输入数字的解决方案(包括退格等)。

7 个答案:

答案 0 :(得分:17)

这将做你想要的:

<span data-bind="text: Interval" ></span>
<input data-bind="numeric, value: Interval" />

http://jsfiddle.net/mbest/n4z8Q/

答案 1 :(得分:6)

仅限数字的固定路线是用户扩展器。

我们无需跟踪按键。在更新之前,更容易订阅observable来拦截值。然后我们可以做一些正则表达式,允许我们评估输入是否是数字。如果输入不是数字,我们将删除非数字字符。因此不允许非数字输入。

<强> FIDDLE

HTML

<input type="text" data-bind="value: myNum, valueUpdate: 'afterkeyup'" />

JS

(function(ko) {

    ko.observable.fn.numeric = function () {
        // the observable we are extending
        var target = this;

        // subscribe to the observable so we can
        // intercept the value and do our custom
        // processing. 
        this.subscribe(function() {
           var value = target();
           // this will strip out any non numeric characters
           target(value.replace(/[^0-9]+/g,'')); //[^0-9\.]/g - allows decimals
        }, this);

        return target;
    };

    function ViewModel() {
        this.myNum = ko.observable().numeric();
    };

    ko.applyBindings(new ViewModel());

})(ko);

答案 2 :(得分:2)

我建议你围绕http://numeraljs.com/制作一个包装器。您只需连接设置,然后在更新时调用输入格式。

答案 3 :(得分:2)

这是我的固定版本,考虑到以上所有内容,但作为真正的价值绑定支持不可观察的对象作为源/目标。

编辑:淘汰赛的缩小版本不会公开 writeValueToProperty 功能和 twoWayBindings 。所以我们应该克隆 writeValueToProperty 并使用 _twoWayBindings 。 我更新了代码以支持缩小版本的淘汰赛。

ko.expressionRewriting._twoWayBindings.numericValue = true;
ko.expressionRewriting.writeValueToProperty = function (property, allBindings, key, value, checkIfDifferent) {
    if (!property || !ko.isObservable(property)) {
        var propWriters = allBindings.get('_ko_property_writers');
        if (propWriters && propWriters[key])
            propWriters[key](value);
    } else if (ko.isWriteableObservable(property) && (!checkIfDifferent || property.peek() !== value)) {
        property(value);
    }
};
ko.bindingHandlers.numericValue = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        $(element).on("keydown", function (event) {
            // Allow: backspace, delete, tab, escape, and enter.
            if (event.keyCode == 46 || event.keyCode == 8 || event.keyCode == 9 || event.keyCode == 27 || event.keyCode == 13 ||
                // Allow: Ctrl+A
                (event.keyCode == 65 && event.ctrlKey === true) ||
                // Allow: . ,
                (event.keyCode == 188 || event.keyCode == 190 || event.keyCode == 110) ||
                // Allow: home, end, left, right.
                (event.keyCode >= 35 && event.keyCode <= 39)) {
                // Let it happen, don't do anything.
                return;
            }
            else {
                if (event.shiftKey || (event.keyCode < 48 || event.keyCode > 57) && (event.keyCode < 96 || event.keyCode > 105)) {
                    event.preventDefault();
                }
            }
        });

        var underlying = valueAccessor();
        var interceptor = ko.dependentObservable({
            read: function () {
                if (ko.isObservable(underlying) == false) {
                    return underlying;
                } else {
                    return underlying();
                }
            },
            write: function (value) {
                if (ko.isObservable(underlying) == false) {
                    if (!isNaN(value)) {
                        var parsed = parseFloat(value);
                        ko.expressionRewriting.writeValueToProperty(underlying, allBindingsAccessor, 'numericValue', !isNaN(parsed) ? parsed : null);
                    }
                } else {
                    if (!isNaN(value)) {
                        var parsed = parseFloat(value);
                        underlying(!isNaN(parsed) ? parsed : null);
                    }
                }
            }
        });
        ko.bindingHandlers.value.init(element, function () { return interceptor; }, allBindingsAccessor, viewModel, bindingContext);
    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        ko.bindingHandlers.value.update(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
    }
}

答案 4 :(得分:1)

实际上,这并不会更新您的观察结果。自定义绑定不完整。在我看来,这只是作为这个想法的一个例子,而不是一个有效的解决方案。

但是,在您链接的问题中,评论中的某个地方实际上有更好的方法。它是使用Knockout扩展器。请参阅http://knockoutjs.com/documentation/extenders.html

上的实时示例1

有几个原因它更好:  1.更强大。例如,您仍然可以在解决方案中粘贴剪贴板中的一串文本。  2.更加人性化。您的解决方案明显禁用了一堆密钥。这根本不是用户友好的。 Knockout提出的解决方案只是确保最终价值是正确的。  3.更好的代码分离和可维护性:您的HTML只能包含一个简单的值'绑定。一旦需求增加,该值应为数字,您只需在视图模型中扩展observable。您所做的唯一更改是在JavaScript中,因为它应该是,因为它是功能,而不是表示。这种变化也很自然,很明显扩展器对可能在计算中使用observable或w / e的人做了什么。

答案 5 :(得分:1)

  

我需要一个只允许输入数字的解决方案(包括   像退格等等。)。

检查这个jquery插件: http://www.texotela.co.uk/code/jquery/numeric/

它允许使用小数分隔符,您可能需要将其分叉以允许其他字符如退格

答案 6 :(得分:0)

您可以改进绑定处理程序以支持valueAccessor

的修改

结合:

ko.bindingHandlers.numeric = {
    init: function (element, valueAccessor) {
        var value = valueAccessor();
        $(element).on("keydown", function (event) {
            // Allow: backspace, delete, tab, escape, and enter
            if (event.keyCode == 46 || event.keyCode == 8 || event.keyCode == 9 || event.keyCode == 27 || event.keyCode == 13 ||
                // Allow: Ctrl+A
                (event.keyCode == 65 && event.ctrlKey === true) ||
                // Allow: . ,
                (event.keyCode == 188 || event.keyCode == 190 || event.keyCode == 110) ||
                // Allow: home, end, left, right
                (event.keyCode >= 35 && event.keyCode <= 39)) {
                // let it happen, don't do anything
                return;
            }
            else {
                // Ensure that it is a number and stop the keypress
                if (event.shiftKey || (event.keyCode < 48 || event.keyCode > 57) && (event.keyCode < 96 || event.keyCode > 105)) {
                    event.preventDefault();
                }
            }
        });

        $(element).change(function () {
            value($(element).val());
        });
    }    
};

在这种情况下,HTML将是

<span data-bind="text: Interval" ></span>
<input data-bind="numeric: Interval" />

FIDDLE