简体   繁体   English

淘汰赛自定义数字绑定

[英]knockout custom numeric binding

I wanted to use this technique: make an input only-numeric type on knockout 我想使用这种技术: 在knockout上创建一个仅输入数字类型

to allow user to enter only numbers. 允许用户只输入数字。

However, this technique doesn't update observable value on UI. 但是,此技术不会更新UI上的可观察值。

HTML: HTML:

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

Binding: 捆绑:

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();
                }
            }
        });
    }    
};

So, binding doesn't allow to enter characters other than numbers, but when focus is lost on input , corresponding observable is not updating (so span elements is not changing). 因此,绑定不允许输入除数字之外的字符,但是当input丢失焦点时,相应的observable不会更新(因此span元素不会更改)。

NOTE: 注意:

I do not need to allow user to enter non numeric characters into input. 我不需要允许用户在输入中输入非数字字符。 I know there are other solution like ko numeric extension that converts everything into numerics, but I do not need this. 我知道有其他解决方案,如ko数字扩展,将所有内容转换为数字,但我不需要这个。 I need a solution that allows to enter only digits (including something like backspace etc.). 我需要一个只允许输入数字的解决方案(包括退格等)。

This will do what you want: 这将做你想要的:

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

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

A solid route for numeric only numbers would be to user an extender. 仅数字数字的可靠路径是用户扩展器。

We don't have to track the keypress. 我们不必跟踪按键。 It is easier to just subscribe to the observable to intercept the value before it updates. 在更新之前,更容易订阅observable来拦截值。 We can then do some regex that allows us to evaluate whether the input is a number or not. 然后我们可以做一些正则表达式,允许我们评估输入是否是数字。 If the input is not a number, we will strip out the non-numeric characters. 如果输入不是数字,我们将删除非数字字符。 Thus allowing no non-numeric input. 因此不允许非数字输入。

FIDDLE : FIDDLE

HTML HTML

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

JS 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);

I would suggest you make a wrapper around http://numeraljs.com/ . 我建议你围绕http://numeraljs.com/制作一个包装器。 You would just hook up the settings and on update you would call format on the input. 您只需连接设置,然后在更新时调用输入格式。

It is my fixed version considering all above but working as real value binding and supporting non-observable objects as source/target. 考虑到上述所有内容,它是我的固定版本,但作为实际值绑定支持非可观察对象作为源/目标。

EDIT :Minified version of knockout does not expose writeValueToProperty function and twoWayBindings . 编辑 :敲除的缩小版本不公开writeValueToProperty函数和twoWayBindings So we should clone writeValueToProperty and use _twoWayBindings . 所以我们应该克隆writeValueToProperty并使用_twoWayBindings I updated code to support minified version of knockout. 我更新了代码以支持缩小版的淘汰赛。

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);
    }
}

Indeed, this does not update your observable. 实际上,这并不会更新您的观察结果。 The custom binding is incomplete. 自定义绑定不完整。 It seems to me this is just intended as an example of the idea, not a working solution. 在我看来,这仅仅是作为这个想法的一个例子,而不是一个有效的解决方案。

However, in the question you linked, there's actually a better approach somewhere in the comments. 但是,在您链接的问题中,评论中的某个地方实际上有更好的方法。 It is to use a Knockout extender. 它是使用Knockout扩展器。 See Live Example 1 on http://knockoutjs.com/documentation/extenders.html 请参阅http://knockoutjs.com/documentation/extenders.html上的实例1

There's a few reasons it's better: 1. More robust. 有几个原因它更好:1。更强大。 For example, you could still paste a string of text from the clipboard in your solution. 例如,您仍然可以在解决方案中粘贴剪贴板中的一串文本。 2. More user-friendly. 2.更加人性化。 Your solution plainly disables a bunch of keys. 您的解决方案明显禁用了一堆密钥。 This is not user friendly at all. 这根本不是用户友好的。 The solution proposed by Knockout just ensures the ultimate value is a correct one. Knockout提出的解决方案只是确保最终价值是正确的。 3. Better code separation and maintainability: your HTML can just contain a plain ol' value binding. 3.更好的代码分离和可维护性:您的HTML只能包含一个简单的值'绑定。 Once a requirement rises that the value should be numerical, you just extend the observable in your viewmodel. 一旦需求增加,该值应为数字,您只需在视图模型中扩展observable。 The only change you make is in the JavaScript, as it should be, since it's functionality, not presentation. 您所做的唯一更改是在JavaScript中,因为它应该是,因为它是功能,而不是表示。 The change also stands on itself, and it's very clear what the extender does to anyone that might be using the observable in calculations or w/e. 这种变化也很自然,并且非常清楚扩展器对可能在计算中使用可观察量或w / e的任何人所做的事情。

I need a solution that allows to enter only digits (including something like backspace etc.). 我需要一个只允许输入数字的解决方案(包括退格等)。

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

it allows decimal separator, you may want to fork it in order to allow other chars like backspace 它允许小数分隔符,你可能想要分叉它以允许其他字符如退格

You can improve your binding handler to support modification of valueAccessor 您可以改进绑定处理程序以支持valueAccessor的修改

Binding: 捆绑:

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());
        });
    }    
};

In this case HTML will be 在这种情况下,HTML将是

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

FIDDLE 小提琴

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM