包装Knockout的hasFocus可在选中时更改元素文本

时间:2014-03-10 16:54:03

标签: knockout.js focus

我有一个名为valueNumber的Knockout绑定处理程序,它在Globalize的帮助下解析并显示数字:

ko.bindingHandlers.valueNumber = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
        // This will be called when the binding is first applied to an element
        // Set up any initial state, event handlers, etc. here

        var observable = valueAccessor(),
            properties = allBindingsAccessor();

        var interceptor = ko.computed({
            read: function () {

                var format = properties.numberFormat || "n2",
                    formattedNumber = Globalize.format(ko.utils.unwrapObservable(observable), format);

                return formattedNumber;
            },
            write: function (newValue) {
                var currentValue = ko.utils.unwrapObservable(observable),
                    numberValue = Globalize.parseFloat(newValue);

                if (!isNaN(numberValue)) {

                    if (numberValue !== currentValue) {
                        // The value has changed so update the observable
                        observable(numberValue);
                    }
                } else if (newValue.length === 0) {
                    if (properties.isNullable) {
                        // If newValue is a blank string and the isNullable property has been set then nullify the observable
                        observable(null);
                    } else {
                        // If newValue is a blank string and the isNullable property has not been set then set the observable to 0
                        observable(0);
                    }
                }
            }
        });

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

使用它非常简单:

<input data-bind="valueNumber: Cost, numberFormat: 'n1', isNullable: true" type="text" value="" />

当输入文本框失去焦点时,将根据numberFormat属性显示该值。因此,如果用户在上面的文本框中输入了“1.123”,那么当他们选中时,“1.1”将在输入中显示,但存储在observable中的值将为1.123。

这就是它变得棘手的地方。

当输入元素获得焦点/成为活动元素时,我想向输入元素中的用户显示完整值(1.123)。我有一些想法,依靠hasFocus,我可以做到这一点,但我不太确定“正确”的方法会是什么样子。

我理想地希望在一个绑定处理程序中包装这一切,而不是引入额外标记的需要。

更新

根据Robert Westerlund的回答,我提出了一个JSFiddle,可以很好地演示解决方案。这基本上是Robert的解决方案,但根据内置hasFocus绑定中使用的约定进行了略微重新设置。

哦,为了完整性,这个解决方案正在使用Globalize 0.1.1。快速浏览一下GitHub仓库后,看起来Globalize的API将在未来某个时候发生变化。

1 个答案:

答案 0 :(得分:0)

总是很难说“正确”的方法是什么,但我会给你一个至少一种方法的样本。首先,添加一个observable以跟踪焦点状态。

var elementHasFocus = ko.observable(element === document.activeElement);

接下来,您需要确保在发生onbluronfocus事件时更改该值。

element.onblur = function(){ elementHasFocus(false); };
element.onfocus = function(){ elementHasFocus(true); };

在创建init计算的observable之前,可以在interceptor方法中添加以上三行。

最后,更新interceptor的读取方法,以确保它根据焦点状态确定值。

read: function () {
    if (elementHasFocus()) {
        return ko.unwrap(observable); // If you use newer versions of knockout, you have a convenient ko.unwrap path to the ko.utils.unwrapObservable method.
    }
    else {
        var format = properties.numberFormat || "n2",
            formattedNumber = Globalize.format(ko.utils.unwrapObservable(observable), format);

        return formattedNumber;
    }
}