简体   繁体   English

在焦点敲除自定义绑定上显示输入的基础值

[英]show underlying value of input on focus knockout custom binding

I have created (please excuse the mess - just hacking it together at the moment!) the following binding handler in knockout 我在淘汰赛中创建了以下绑定处理程序(请原谅,现在只是将它们一起砍掉!)

The desired functionality is that if a field is numeric then it will be formatted to 'X' decimal places (default 2) when displaying but the underlying value is whatever is entered. 所需的功能是,如果一个字段为数字,则在显示时将其格式设置为小数点后缀“ X”(默认为2),但输入的基础值将为小数。

All works fine, but I want to add the functionality that when an input is focused then it shows the actual value and I just have no idea how to do this. 一切正常,但是我想添加一个功能,当输入成为焦点时,它会显示实际值,我只是不知道该怎么做。

ie

  1. user enters 1.1121 into an input 用户在输入中输入1.1121
  2. when they leave the input it formats to 1.11 当他们离开输入时,其格式为1.11
  3. if they go back into the input (focus) then it displays 1.1121 for editing 如果他们返回输入(焦点),则会显示1.1121进行编辑

It is point 3 that I have no idea how to achieve as at the moment it shows 1.11 and then over-writes on blur?? 是第3点,我不知道该如何实现,因为它现在显示1.11,然后在模糊时覆盖?

Can anyone point me in the right direction - basically where do I access the underlying value on focus and replace the displayed text with the underlying value?? 谁能为我指出正确的方向-基本上我可以在哪里访问基础值并将焦点替换为基础值?

for brevity I have removed some other 'decoration' code that wraps the inputs as they are not relelvant. 为简便起见,我删除了一些其他的“装饰”代码,这些代码包装了输入,因为它们并不相关。

Thanks in advance. 提前致谢。

    ko.bindingHandlers.specialInput = {
    init: function (element, valueAccessor, allBindingsAccessor) {

        var value = valueAccessor();

        var decimals = allBindingsAccessor().decimals || 2;
        var formatString = "";

        var interceptor = ko.computed({
            read: function () {
                if(isNumeric(ko.unwrap(value))){

                    //to do if time - replace this with a function that will accept any number of decimals
                    if(decimals == 0){
            formatString = "0,0";
        }
                    if(decimals == 1){
            formatString = "0,0.0";
        }
                    if(decimals == 2){
            formatString = "0,0.00";
        }
                    if(decimals == 3){
            formatString = "0,0.000";
        }
                    if(decimals == 4){
            formatString = "0,0.0000";
        }
                    if(decimals == 5){
            formatString = "0,0.00000";
        }


                return numeral(ko.unwrap(value)).format(formatString);
                }else{
                    return ko.unwrap(value);
                }
            },
            write: function (newValue) {
                if ($.trim(newValue) == '')
                    value("");
                else
                   if(isNumeric(newValue)){ 
                    value(numeral().unformat(newValue));
                value.valueHasMutated();
                   }else{
                    value(newValue);
                    value.valueHasMutated();
                   }
            }
        }).extend({notify: 'always'});




        if (element.tagName.toLowerCase() == 'input') {
            ko.applyBindingsToNode(element, {
                value: interceptor
            });
        } else {
            ko.applyBindingsToNode(element, {
                text: interceptor
            });
        }


    },
    update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {

        var value = ko.unwrap(valueAccessor());

        return ko.bindingHandlers.value.update(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);

    }
};

function isNumeric(n) {
    return !isNaN(parseFloat(n)) && isFinite(n);
}

I wouldn't implement this with an interceptor computed. 我不会用计算出的interceptor来实现这一点。

I'd rather do the following: 我宁愿执行以下操作:

In the init register event handlers for focus and blur in the init: init注册事件处理程序中,用于在init进行focusblur处理:

  • on the focus handler, you have to show the underlying value in the input focus处理程序上,您必须在输入中显示基础值
  • on the blur handler, you have to store the number in the textbox, and show the rounded value in the input blur处理程序上,您必须将数字存储在文本框中,并在输入中显示四舍五入的值

In the update you have to store the real value, and show it in the textbox. update您必须存储实际值,并将其显示在文本框中。 Most probably the textbox won't have the focus when you update the value, so you should be safe showing the rounded value. 更新值时,文本框很可能没有焦点,因此应该放心显示四舍五入的值。 However, if you think that in some cases it can be focused, you can do something like this to test it to decide how to show the value: Using jQuery to test if an input has focus 但是,如果您认为在某些情况下可以将其聚焦,则可以执行以下操作来测试它以确定如何显示该值: 使用jQuery测试输入是否具有焦点

pseudocode 伪码

ko.bindingHandlers.yourBindingName = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
  var $element = $(element);

  $element.on('focus', function() {
    // Show raw value:
    $element.val(/* raw value */);
  });

  $element.on('blur', function() {
    // Update the observable with the value in the input
    ko.unwrap(valueAccessor())( /* get raw value from input */);
    // Show the rounded value
    $element.val(/* rounded value */);
  });

  // Update will be called after init when the binding is first applied,
  // so you don't have to worry about what it's initially shown
},

update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
    // When the value changes, show it in the input
    $.element.val(/* if focused show raw, if not, show roundede*/);
}

}; };

If you are sure that you are only going to use it with input and writable observables, this code is safe. 如果您确定只将其与input和可写可观察对象一起使用,则此代码是安全的。 If you have doubts about it, you should add many checks like cheking the kind of element to use jQuery .val() or .text() , check if the binding expression is a writeable observable to update its value, and so on. 如果对此有疑问,则应添加许多检查,例如检查使用jQuery .val().text()的元素的种类,检查绑定表达式是否可写,以观察其值,等等。

NOTE: thereis something which is overseen many times: disposing of objects that we no longer need when the element is destroyed (that can happen for example with 'if', 'whit' or 'template'). 注意:有很多事情需要监督:销毁元素时我们不再需要的对象(例如,如果使用'if','whit'或'template',则可能发生)。 In this case I think you don't need to do that, but, please, see this: Custom disposal logic if you think you need to destroy something. 在这种情况下,我认为您不需要这样做,但是请查看以下内容: 自定义处理逻辑(如果您认为需要销毁某些东西)。

There's nothing wrong with using jQuery in a binding handler, but you could also do this pretty simply with existing binding handlers. 在绑定处理程序中使用jQuery并没有错,但是您也可以使用现有的绑定处理程序非常简单地完成此操作。 It's the sort of thing that could be rolled into a component to be re-used (although I didn't do that in my example). 可以将其整合到组件中以进行重用(尽管在我的示例中我没有这样做)。

You just need a backing store for your value, and the computed returns either the backing store or the formatted backing store, depending on whether the input has focus (using the hasFocus binding). 您只需要一个值的后备存储,然后计算的结果就会返回后备存储或格式化的后备存储,具体取决于输入是否具有焦点(使用hasFocus绑定)。

 vm = (function() { var editing = ko.observable(false), backingStore = 0, value = ko.computed({ read: function() { return editing() ? backingStore : (+backingStore).toFixed(2); }, write: function(newValue) { backingStore = newValue; } }); return { editing: editing, value: value } }()); ko.applyBindings(vm); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script> <input data-bind="hasFocus: editing, value: value" /> <input /> 

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

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